다음은 상속과 합성의 특징을 표로 정리한 것이다. 코드 재사용이라는 동일한 목적을 제외하면 모두 다르다.
상속 | 합성 | |
---|---|---|
목적 | 코드 재사용 | 코드 재사용 |
재사용 객체 | 부모 클래스 | 부분 객체 |
의존성 | 컴파일타임 | 런타임 |
관계 | IS-A | HAS-A |
상속은 부모의 내부 구현에 대해 상세하게 알아야 한다. 하지만 합성은 구현에 의존하지 않는다. 합성은 퍼블릭 인터페이스에 의존한다. 따라서 합성을 사용하면 객체의 내부 구현이 변경되더라도 영향을 최소화할 수 있기 때문에 변경에 더 안정적인 코드를 얻을 수 있게 된다. 고로 대부분의 경우 변경에 유연하게 대처할 수 있는 합성이 정답일 가능성이 높다.
객체 합성은 클래스 상속의 대안이다. 객체를 합성하려면 합성할 객체들의 인터페이스를 명확하게 정의해야만 한다. 이런 재사용을 블랙박스 재사용이라고 하는데 객체 내부는 공개되지 않고 인터페이스를 통해서만 재사용되기 때문이다.
10장에서 상속의 문제 세가지를 살펴봤다.
합성을 사용하면 이 세 가지 문제를 해결할 수 있다. 부모 클래스의 인스턴스를 자식 클래스의 인스턴스 변수로 선언하면 된다.
HashTable 클래스와 Properties 클래스 사이의 상속 관계를 합성 관계로 바꿔보자. 상속을 제거하고 Hashtable을 Properties의 인스턴스 변수로 포함시키면 합성 관계로 변경할 수 있다. Stack도 마찬가지다.
이제 불필요한 오퍼레이션들이 Properties과 Stack의 퍼블릭 인터페이스를 오염시키지 않는다. 의도치 않은 동작의 가능성도 배제한다.
이 또한 HashSet 인스턴스를 내부에 포함해 HashSet의 퍼블릭 인터페이스에서 제공하는 오퍼레이션으로 기능을 구현하면 된다.