11장 - HONGDAE-OBJECT/OOP GitHub Wiki
11장 합성과 유연한 설계
-
코드 재사용을 위해서는 객체 합성이 클래스 상속보다 더 좋은 방법이다. [GOF94]
-
is a 관계 : 화이트박스 재사용, 상속으로 코드 재사용
-
has a 관계 : 블랙박스 재사용, 위임으로 기능의 재사용
-
상속은 부모 클래스의 내부 구현에 대해 상세하기 알아야 하기 때문에 자식 클래스와 부모 클래스 사이의 결합도가 높아질 수 밖에 없다.
01. 상속을 합성으로 합성으로 변경하기
불필요한 인터페이스(기능) 상속 문제
- 부적합한 부모 클래스의 오퍼레이션(기능) 상속됨
- Stack 와 Properties 는 자료구조가 다르다!
- 합성도 똑같은 문제 발생
메서드 오버라이딩 오작용 문제
- 부모 클래스의 잘 만들어진 메서드는 수정할 필요가 없다!
- addCount, add 는 재구현의 대상이 아님
부모 클래스와 자식 클래스의 동시 수정 문제
- 구현 자체가 이상함
- 상속은 부모 코드를 그대로 두고 자식 클래스로 문제를 해결
- super 를 쓸 경우 부모클래스의 코드를 이해하거나 수정해야 함
- 부모의 멤버객체, 멤버변수는 재사용 대상이 아님
- 위임으로 해결할 수 있지만 그렇다고 코드 반복이 줄어드는건 아님 질문) 부모클래스와 자식클래스간는 어떤 결합도? 내용 결합?
02. 상속으로 인한 조합의 폭발적인 증가
- 하나의 기능을 추가하거나 수정하기 위해 불필요하게 많은 수의 클래스를 추가하거나 수정해야 한다.
- 단일 상속만 지원하는 언어에서는 상속으로 인해 오히려 중복 코드의 양이 늘어날 수 있다. (단일 상속은 쓸때없는 생각을 차단)
기본 정책과 부가 정책 조합하기
- 기본정책, 부가정책[사진]


- 4개의 상태를 조합 = 10가지의 흐름이 생김
- 상속을 사용할 문제는 아닌 것 같음.
- 부모 클래스가 모호하고 자식 클래스만 사용해야 함.
- 상속은 부모클래스와 자식클래스 모두 사용해야 함을 원칙
상속을 이용해서 기본 정책 구현하기
기본 정책에서 세금 정책 조합하기
기본 정책에 기본 요금 할인 정책 조합하기
중복 코드의 덫에 걸리다
- 무리한 상속


03. 합성 관계로 변경하기
상속관계는 컴파일 타임에 결정되고 고정되기 때문에 코드를 실행하는 도중에는 변경할 수 없다.(있다!) 예제로 나온 코드도 컴파일 타임에 결정됨. (367p)

기본 정책 합성하기
부가 정책 적용하기
기본 정책과 부가 정책 합성하기
새로운 정책 추가하기

- 클래스 하나만 추가하면 되는건 맞는 이야기
- 클래스 하나만 추가한다 하더라도 중복코드는 제거 못함
- 생/구/행 중 행위 패턴인 이터레이터 패턴으로 해결
객체 합성이 클래스 상속보다 더 좋은 방법이다.
- 상속과 합성은 목적이 달라 비교 대상은 아님
- 결합도는 하나의 모듈이 변경되거나 오류가 발생했을때 다른 모듈에 미치는 영향
- 상속과 합성의 결합도도 비교 대상이 아님
04. 믹스인
- 객체의 추상적인 인터페이스에 의존 : 기능을 사용할 테니 필요할때 알아서 맞춰라.
- 믹스인 : 추상화 클래스
- 상속은 정적이지만 믹스인은 동적이다
- 핸드폰 과금 시스템의 목적은 기본 정책 과 부가 정책을 자유롭게 조합할 수 있는 설계
package com.code5.biz.comm002;
/**
* @author skmpr
*
*/
abstract class 핸드폰요금계산 {
abstract 기본정책 기본정책();
abstract 부가정책 부가정책();
/**
* @return
*/
public long 지불할금액() {
long 월요금 = 기본정책().요금();
long 지불할금액 = 부가정책().요금계산(월요금);
return 지불할금액;
}
}
package com.code5.biz.comm002;
/**
* @author skmpr
*
*/
class 일반요금_할인없음 extends 핸드폰요금계산 {
기본정책 기본정책() {
return new 일반요금제();
}
부가정책 부가정책() {
return new 할인50();
}
/**
* @param xxx
*/
public static void main(String[] xxx) {
// 템플릿 패턴
핸드폰요금계산 a = new 일반요금_할인없음();
System.out.println(a.지불할금액());
}
}