단일 책임 원칙(SRP)이란 하나의 클래스는 하나의 책임만 가지며, 그 책임에 대해 완전히 캡슐화 해야 하는 원칙이다.
class Food:
"""추상화 과정이 필요한 Food 클래스"""
def __init__(self, name, food):
self.name = name
self.food = food
def eat_food(self):
if self.food == "치킨":
print(f"{self.name}가 {self.food}를 먹는다")
elif self.food == "피자":
print(f"{self.name}가 {self.food}를 먹는다")
예제를 먼저 보자. 위의 Food 클래스에서는 객체 생성시에 음식을 정의하고, 음식에 따라 if문을 처리한다. 즉 Food 클래스는 음식이 다른 두가지 케이스에 대한 책임을 동시에 가지고 있다. 이러한 경우 Food 클래스를 추상화시킴으로써 해결할 수 있다.
추상 클래스란 클래스 내부에 구현되지 않은 메서드를 한가지 이상 가지고 있을때, 추상 클래스라 부른다. 이 구현되지 않은 메서드는 자식 클래스에서 반드시 구현 해주어야 한다. 즉, 반드시 재정의(메서드 오버라이딩)하라는 뜻이다. 이 추상클래스는 부모 클래스를 설계할때, 자식 클래스에 이 함수는 반드시 존재하여야 하며 자식 클래스 각 성격마다 메서드의 내부 구현이 다를것 같으니 부모 클래스에서는 해당 메서드를 비워두지만 꼭 구현해야하기 때문에 강제한다. 는 뜻이다.
from abc import *
class FoodBase(metaclass=ABCMeta):
"""추상화 과정을 한 Food 클래스"""
def __init__(self, name):
self.name = name
@abstractmethod
def eat_food(self):
pass
class Chicken(FoodBase):
def __init__(self, name):
super().__init__(name)
self.food = "치킨"
def eat_food(self):
print(f"{self.name}가 {self.food}를 먹는다")
class Pizza(FoodBase):
def __init__(self, name):
super().__init__(name)
self.food = "피자"
def eat_food(self):
print(f"{self.name}가 {self.food}를 먹는다")
위와 같이 추상클래스, FoodBase 클래스를 만들어 주었다. 추상 클래스를 사용하려면 반드시 abc 모듈을 import 해야 한다. 또한 추상 메서드는 메서드 이름 위에 @abstractmethod 라는 것을 붙여야 하고, 추상 클래스에는 (metaclass=ABCMeta)라는 것을 붙여 주어야 한다. 이것도 추상 클래스를 만들수 있는 클래스를 상속을 받는것이다.
기본적으로 생성시에는 이름만 받고 이를 상속받은 클래스들은 eat_food를 구현하게끔 하였다. 그리고 FoodBase를 상속받는 Chicken 클래스와 Pizza 클래스를 정의함으로써, 음식이 다른 경우에 대해 각 클래스가 유일한 책임을 가지도록 하였다. 이렇게 우리가 SOLID에서 단일 책임 원칙에 준수하게 코드를 작성하는 방법을 살펴보았다.
FoodBase 클래스에서는 보다 높은 추상화 과정을 통해서 각 클래스가 하나의 책임만 가지도록 설정하였다. 이렇게 단일 책임 원칙을 지킨 경우에 클래스에 대한 외부 영향도를 최소화 할 수 있으며, 결국 유지보수나 확장 면에서 보다 효율적일 수 있다.