데코레이션 패턴은 OCP(Open-closed Principle) 디자인 원칙을 준수합니다.
클래스는 확장에 열려있어야 하고 코드 변경에 대해서는 닫혀 있어야 한다.

하지만 모든 클래스에 적용한다기 보다는 가장 바뀔 확률이 높은 부분에 중점적으로 OCP를 적용하는 것이 좋습니다(시간 대비 효용성을 고려해야 하죠).

음식을 예로 들어봅시다.
음식에서 가장 많이 바뀔 수 있는 부분은 첨가물의 종류입니다.
첨가물 구성요소의 합이 바로 그 음식물과 같다는 생각은 현실세계에선 부질없긴 하지만, 그렇다고 (마음 아프지만)가정하고 생각해 봅시다.
다음은 음식 추상 클래스입니다.
public abstract class Food{
Food food;
public abstract void throwIt();    // 던져넣는 메소드
}

일단, 가장 좋은 점은 무엇일까요?

1. 음식에 계란을 더 추가한다면, 기존 음식에 들어가는 첨가물들은 전혀 계란(계란의 가격이라던지 맛이라던지)을 신경쓰지 않아도 됩니다(먹는 사람은 신경 쓰겠죠 - 전 계란을 매우 좋아합니다 ㅋㅋㅋ). 즉, 원래 있던 코드는 그대로 있고, 새로운 계란 클래스를 만들어 주기만 하면 됩니다.
public class Egg extends Food{
public Egg(Food ingre){
this.ingredient = ingre;
}
public void throwIt(){
throwScrambleEgg();   // 스크램블 에그를 만들어서 던집니다.
food.throwIt();
}
...
}

2. 다른 첨가물과 같은 사용 방식를 고수하므로 음식이 첨가물을 넣는 방법을 바꿀 필요가 없습니다. 그냥 던져(throwIt) 넣으세요. 즉, 첨가물들은 모두 같은 인터페이스를 사용하기 때문에 첨가물을 실제로 사용하는 음식 클래스에선 첨가물 추가 방식을 바꿀 필요가 없는 것입니다. 단순히 음식 클래스를 를 구현한 오브젝트(계란, 파, 소금, 고기 등.. 온갖 것이 될 수 있습니다)의 throwIt 메소드를 사용하기만 하면 됩니다.
Food whatADeliciousfood = new Egg(new SpringOnion(new Salt(new Meat));
whatADeliciousfood.throwIt();     // 계란, 파, 소금, 고기를 고유한 방식으로 던집니다.

이것은 자바 I/O를 담당하는 클래스들의 행동방식과 완전히 같습니다. InputStream을 구현한 클래스 각각이 자신의 고유한 행동방식을 메소드에서 구현하고 있기 때문입니다. 그래서 단지 읽고(read) 쓰기(write)를 시키기만 해도 감싸준 모든 InputStream의 구현체들이 자신들의 고유한 방식으로 일을 하게 되는 것입니다.

참고 : Head First Design Patterns 3장 데코레이터 패턴
저작자 표시 비영리
신고
posted by purecolor