"클래스 상속보다 객체 합성(위임)을 써라"는 원칙과, 상속 관계를 위임으로 바꾸는 두 리팩터링. 상속을 쓰지 말라는 뜻이 아니라 과용에 대한 반작용으로 나온 말이다.
상속의 두 가지 한계
- 한 축만 고를 수 있다: 사람을 나이대와 소득 수준으로 동시에 나누고 싶어도 서브클래스는 한 기준만 택할 수 있다
- 강하게 결합된다: 부모를 고치면 자식이 깨지기 쉽고, 부모와 자식이 다른 팀·모듈에 있으면 더 위험하다
위임은 둘 다 해결한다. 여러 이유로 여러 객체에 위임할 수 있고, 위임 관계는 필요한 인터페이스만으로 이어진다.
두 리팩터링
- 슈퍼클래스를 위임으로(Replace Superclass with Delegate): 부모의 기능 중 자식에게 맞지 않는 게 많을 때. 유명한 나쁜 예가 Java의
Stack extends Vector다. 스택에 어울리지 않는 리스트 연산이 전부 노출된다. 리스트를 필드로 두고 필요한 기능만 전달하는 편이 낫다 - 서브클래스를 위임으로(Replace Subclass with Delegate): 변형 동작을 별도 위임 객체에 담아 부모가 그 객체를 들고 있게 한다. 상속 축을 다른 용도로 비워 둘 수 있다
상속 포기(Refused Bequest) 냄새
자식이 부모의 동작은 쓰면서 인터페이스는 따르고 싶지 않다면 상속이 잘못된 것이다. 부모가 쓰이는 모든 자리에 자식을 넣어도 문제없어야 한다는 리스코프 치환 원칙(Liskov Substitution Principle)을 깨기 때문이다.
파울러의 조언은 실용적이다. 처음에는 단순한 상속으로 시작하고, 문제가 생기면 위임으로 갈아탄다. "어느 하나만 고집하지 말고 적절히 섞어 쓰라"는 것이다. 전략 패턴과 데코레이터 패턴은 합성을 쓰는 대표 패턴이고, React가 상속 대신 합성을 권하는 것도 같은 흐름이다(컴파운드 컴포넌트 패턴, 믹스인).
출처: 『리팩터링 2판』 마틴 파울러 (원서 Refactoring, 2nd Edition) · refactoring.com: Replace Superclass with Delegate · refactoring.com: Replace Subclass with Delegate · Refactoring.Guru: Refused Bequest