상속과 합성

‘Gof의 디자인 패턴’에서는 “Favor object composition over class inheritance”라고 말한다. 이를 해석하면 “객체 합성이 클래스 상속보다 더 나은 방법이다”라는 의미이다.

객체지향 시스템에서 기능의 재사용을 위한 가장 대표적인 두 가지 방법이 상속과 합성이다. 디자인 패턴에서는 상속을 통한 재사용을 ‘white-box reuse’라고 하고 합성을 통한 재사용을 ‘black-box reuse’라고 한다.

먼저, 상속에 대해 살펴보자. 우리가 어떤 객체를 상속하면 private으로 선언되지 않은 모든 변수와 메서드, 생성자가 하위클래스에 노출된다. 이렇게 하위클래스에서 수퍼클래스의 내부가 보인다는 의미로 디자인 패턴에서는 상속을 통한 재사용을 ‘white-box reuse’라고 말하는 것이다. 투명한 하얀 상자 안에 어떤 것이 들어있다면 우리는 밖에서 그것을 볼 수 있을 것이다.

상속의 장점은 오버라이딩을 통해 수퍼클래스의 구현을 손쉽게 재정의할 수 있다는 것이다. 그럼에도 불구하고 상속을 이용해서 재사용할 때, 시스템 설계자들은 무엇을 못마땅하게 여길까?

세 가지 이유가 있는데, 하나는 앞서 말했듯이 수퍼클래스가 하위클래스에 불필요하게 많은 부분이 노출된다는 것이다. 이것은 객체지향의 원칙 중 하나인 캡슐화에 위배되고 또한 하위클래스가 수퍼클래스의 구현에 종속되고, 수퍼클래스 구현이 변경되어야 할 경우가 생기면 하위클래스도 변경해야 하는 문제점이 발생할 수 있다.

또 다른 하나는 컴파일 시점에 객체의 형식이 이미 결정된다는 것이다. 사실 이것이 가장 큰 이유기도한데, “A 클래스가 B 클래스의 수퍼클래스다”라는 식의 정보가 이미 컴파일 시점에 결정되어 버리기 때문에 런타임 시점에서 상속받은 수퍼클래스의 구현을 변경할 수 없어 시스템의 유연성이 떨어진다는 단점이 생긴다.

마지막 하나는 시스템이 진화할수록 상속 관계가 복잡해져서 그 시스템의 상속 트리를 정확하게 이해하고 있지 않으면 시스템의 수정과 확장에 손을 댈 수 없는 상황까지 발생할 가능성이 생기기 때문이다.

지금까지 상속의 단점에 대해서만 너무 부각시킨 느낌이 든다. 하지만 상속은 분명 객체지향 프로그래밍에서 가장 중요한 개념 중 하나고 그 장점과 유용성도 많다.

이제 합성에 대해 알아보자. 객체 합성은 객체가 다른 객체의 참조자를 얻는 방식으로 런타임시에 동적으로 이뤄진다. 따라서 다른 객체의 참조자를 얻은 후 그 참조자를 이용해서 객체의 기능을 이용하기 때문에 해당 객체의 인터페이스만을 바라보게 됨으로써 캡슐화가 잘 이뤄질 수 있다. 이렇게 각 객체의 캡슐화를 유지할 수 있기 때문에 시스템 설계자들이 상속보다 합성을 더 선호하는 것이다. 또한 합성이 상속과 달리 참조 객체의 내부를 볼 수 없기 때문에 디자인 패턴에서 “black-box reuse’라고 말하는 것이다.

하지만 합성에도 오용에 따른 담점과 주의해야 할 점이 존재한다. 우선 합성은 객체 간의 관계가 수직관계가 아닌 수평 관계가 된다. 따라서 큰 시스템에서 많은 부분에 걸쳐 합성이 사용될 때 객체나 메서드명이 명확하지 않으면 코드가 가독성이 떨어지고 이해하기 어려워지게 된다. 따라서 합성을 사용할 때에는 그 용도에 따라 클래스들을 패키지로 적적하게 분리해야 하고 각각의 사용 용도가 명확하게 드러나도록 인터페이스를 잘 설계해야 한다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 항목은 *(으)로 표시합니다