Composition Over Inheritance

Park Choong Ho·2021년 2월 2일
0

Composition over Inheritance

Composition over Inheritance, 즉 객체 composition(적절한 한글말을 못정하겠네요 아시는 분들은 댓글 남겨주시면 감사하겠습니다. ㅎㅎ)이 inheritance보다 우선시 된다는 말입니다. 이게 대체 무슨 뜻인지 살펴보겠습니다.

# 1) 직접 상속 받는 예시
class Employee:
    pass
    
class Salesman(Employee):
    def get_type(self):
        return "Sales"

class Manager(Employee):
    def get_type(self):
        return "Manager"
        
# 2) 간접 상속하는 예시
class Type:
    def get():
        raise NotImplemented

class SalesType(Type):
    def get():
        return "Sales"

class ManagerType(Type):
    def get():
        return "Manager"

class Employee:
    def __init__(self, type,Type):
        self.type = type
    def get_type(string):
        return self.type.get()

요런 예시가 있다고 합시다. 위 예시는 딱 보면 이해할 수 있는 코드입니다. Salesman과 Manager가 Employee를 상속하고 있는 설계인것을 직관적으로 알 수 있습니다. 아래 코드는 타입이라는 클래스를 Employee가 생성자에서 인자로 받고 있고 SalesType과 ManagerType 클래스가 Type 클래스를 상속받고 있습니다.

여러분들은 어떻게 느끼실지 모르지만 제가 느끼기에는 현재는 아래코드가 더 복잡해 보입니다. 타입을 얻고 싶을 때 get만 하면 되는 것을 괜히 한번더 감싸서 get_type method를 호출하는 것도 맘에 안듭니다. 실제로 코드가 더 길기도 하구요. 실제로 간단한 예시에서는 inheritance가 composition을 능가할때도 있습니다. (실제 비즈니스 로직이 그렇게 복잡하지 않은 대다수의 경우에는 그렇습니다.) 그럼 대체 composition over inheritance는 어디서 나온 말이 되는 걸까요?

어느날 비즈니스 로직이 바뀌어서 직원의 종류가 아닌 직급이 추가되었다고 가정해봅시다. 쉽게 Level1, Level2, Level3가 생겼다고 해보겠습니다. 이를 상속으로 해결한 첫번째 코드에서는 어떻게 되는 코드가 구성될까요?

# 1) 직접 상속 받는 예시
class Employee:
    pass
    
class SalesLV1Person(Employee):
    def get_type(self):
        return "SalesLV1"
        
class SalesLV2Person(Employee):
    def get_type(self):
        return "SalesLV2"
        
class SalesLV3Person(Employee):
    def get_type(self):
        return "SalesLV3"
        
class ManagerLV1Person(Employee):
    def get_type(self):
        return "ManagerLV1"
        
class ManagerLV2Person(Employee):
    def get_type(self):
        return "ManagerLV2"
        
class ManagerLV3Person(Employee):
    def get_type(self):
        return "ManagerLV3"

이렇게 클래스가 2개에서 6개로 늘어나게됩니다. 단순 Sales와 Manager로 구분되었던 경우의 수가 직급이라는 개념이 추가되면서 2 * 3 총 6개의 클래스가 되어 버린 것이죠. 그런데 여기에 또 새로운 개념이 추가된다면 어떻게 될까요? 연봉이라는 개념이 추가된다면? 그런데 연봉이 총 4단계로 나누어진다면? 벌써 클래스가 24개가 됩니다. 여기에 혹시 또 다른 것이 추가된다면? 개발자가 관리해야할 클래스의 개수는 기하급수적으로 늘어나게됩니다. 실력있는 개발자라면 여기서 아! 상속이 아닌 composition을 떠올리며 코드를 전환할 준비를 하게 될 것입니다.

class Level:
    def get():
        raise NotImplemented

class Level1(Level):
    def get():
        return "Level1"
        
class Level2(Level):
    def get():
        return "Level2"
        
class Level3(Level):
    def get():
        return "Level3"


class Type:
    def get():
        raise NotImplemented

class SalesType(Type):
    def get():
        return "Sales"

class ManagerType(Type):
    def get():
        return "Manager"

class Employee:
    def __init__(self, type: Type, level: Level):
        self.type = type
        self.level = level
    def get_type(string):
        return self.type.get()
    def get_level(string):
        return self.level.get()

이렇게 composition을 활용하면 plugInPlay를 할 수 있습니다. Employee 클래스에 Level클래스를 주입시킬 수 있습니다. 또한, 연봉이라는 개념이 추가된다고 해도 그냥 그에 해당하는 클래스를 만들고 Employee에 주입시키면 됩니다. inheritance로 이를 구현하려고 하면 클래스의 개수가 24개까지 올라가는 반면에 composition은 11개가 되겠지요. 새로운 개념이 추가될수록 composition over inheritance의 의미는 점점 더 커지게 될것입니다.

hasA isA개념도 같이 갈 수 있습니다. 이 두가지는 장단점이 있는데, hasA 구조는 A를 여기저기 사용할 수 있다는 장점이 있고 isA 구조는 더 간단하다는 장점이 있습니다.

Summary

이렇게 composition over inheritance의 의미와 실제 예시를 공부해보았습니다. 사실 실제 코드에서는 상속을 많이 사용하긴합니다. 그런데 많은 개발자가 너무 상속만 활용해서 유지보수가 힘든 코드를 만드는 경우가 빈번해서 우선은 composition에 무게를 두자는 말이 나온 것이라 합니다. 복잡한 비즈니스 상황에서 개발자는 언제나 변화에 유연한 코드를 짜야하니까요.

profile
백엔드 개발자 디디라고합니다.

0개의 댓글