티스토리 뷰
정의
- 기존 상속구조에서 부모 코드를 변경하지 않고, 런타임에 동적으로 기능을 추가하기 위한 pattern
- 재료가 추가되면 부모클래스(Beverage)에 method가 계속 추가됨.
- 재료가 변경되거나, 가격이 변경되면 부모클래스(Beverage) 수정 필요함.
- 절대 사용하지 않을 재료의 method도 모든 음료가 상속받게 됨.
부모 클래스(Beverage)에 존재하던 유동적인 재료 부분을 모두 각각의 class로 뺐으므로 재료에 대한 정보가 변경되더라도 기존 부모클래스를 수정할 필요 없음. 재료 class를 수정하거나 추가하면 됨.. OCP을 따름.
예제
문제상황
먼저 coffee 가게에서 각 음료의 가격을 알 수 있는 system을 개발한다고 할 때,
일반적인 설계구조를 본 뒤, Decorator pattern을 적용하여 개선해 보자.
1. HouseBlend, DarkRoast, Decaf, Espresso 의 가격을 알 수 있는 class 설계
2. 각 음료에 mocha, milk, wheeping 등 재료가 추가 될 수 있으므로 상위 클래스에 관련 기능 추가.
위 설계의 문제점?
위 설계는 중요한 디자인 원칙인 OCP(Open-Closed Principle) 에 적합하지 않음.
클래스는 확장에 대해서는 열려 있어야 하지만, 코드 변경에 있어서는 닫혀 있어야 한다.즉, 기존 코드는 수정하지 않고, 기능을 확장할 수 있는 설계.
개선방법
각각의 재료를 Decorator class로 빼보자!
// 최상위 추상클래스인 Beverage
public abstract class Beverage{
public abstract int cost();
}
public class HouseBlend extends Beverage{
public int cost() {
return 3000;
}
}
public class DarkRoast extends Beverage{
public int cost() {
return 2000;
}
}
public class Decaf extends Beverage{
public int cost() {
return 1000;
}
}
public class Espresso extends Beverage{
public int cost() {
return 500;
}
}
// decorator class 는 다시 Decorator를 가질 수 있음.
public abstract Decorator extends Beverage{
private Beverage beverage;
public int cost() {
beverage.cost();
}
}
public class Whip extends Decorator{
@overriding
public int cost() {
return 30 + super.cost();
}
}
public class Mlik extends Decorator{
@overriding
public int cost() {
return 20 + super.cost();
}
}
public class Soy extends Decorator{
@overriding
public int cost() {
return 10 + super.cost();
}
}
public class Mocha extends Decorator{
@overriding
public int cost() {
return 5 + super.cost();
}
}
public class Main{
public static void main(String[] args) {
Beverage espresso = new Espresso();
System.out.println("espresso cost = " + espresso.cost()); // 500
Beverage mochaEspresso = new Mocha(espresso);
System.out.println("mochaEspresso cost = " + mochaEspresso.cost()); // 505
Beverage whipMilkSoyHouseBlend = new Whip(new Milk(new Soy(new HouseBlend())));
System.out.println("whipMilkSoyHouseBlendcost = " + mochaEspresso.cost()); // 3060
}
}
결론
서브클래스를 만드는 방식으로 행동을 상속받으면 그 행동은 컴파일 시에 완전히 결정(정적)되며 모든 서브클래스에서 똑같은 행동을 상속 받는다.
하지만 구성을 통해 객체의 행동을 확장하면 실행중에 동적으로 행동을 설정할수 있다.(동적)
장점
- 기본 데이터에 첨가할 기능이 다양하고 일정하지 않을 때, 기존 code를 건드리지 않고 동적으로 기능 확장을 할 수 있으므로 용이.
단점
- 데코레이터 패턴을 이용해서 디자인 하다 보면 잡다한 클래스들이 많아 질 수 있다.
- 코드 가독성이 떨어진다. 구조를 이해하기 자세히 보기 전에는 이해하기 어려움.
Java에서 적용 예
java IO 입출력 에서 Decorator 패턴이 적용 되어 있다.
BufferedReader br = new BufferedReader(new FileReader(new File("test.txt")));
'Programing > DesignPattern' 카테고리의 다른 글
Composite 패턴 (0) | 2016.08.24 |
---|---|
Singleton 패턴 (0) | 2016.08.24 |
Mediator 패턴 (0) | 2016.08.22 |
[디자인패턴] 2. Adapter 패턴 - 바꿔서 재이용하기 (0) | 2013.02.05 |
[디자인 패턴] 1. Iterator 패턴 - 순서대로 지정해서 처리하기 (0) | 2013.02.04 |
댓글