데코레이터 패턴: 기본 기능에 옵션을 추가하는 경우 유용한 패턴
기존 코드: RoadDisplay는 기본 도로 표시 기능을 제공하는 클래스이다. RoadDisplayWithLane은 기본 도로 표시 기능에 추가적으로 차선을 표시하는 클래스이다.
// 기본 도료 표시 클래스 class RoadDisplay{ public void draw() { System.out.println("도로 기본 표시"); } } // 기본 도로 표시 + 차선 표시 클래스 class RoadDisplayWithLane extends RoadDisplay{ public void draw() { super.draw(); drawLane(); } private void drawLane() { System.out.println("차선 표시"); } } public class Client{ public static void main(String[] args) { RoadDisplay road=new RoadDisplay(); road.draw(); RoadDisplay roadWithLane=new RoadDisplayWithLane(); roadWithLane.draw(); } }
문제점: 옵션이 추가될 때마다 클래스가 한 개씩 늘어난다. 예를 들어 ‘기본 도로 표시’ 기능에 ‘교통량 표시’를 하는 옵션이 추가되면 ‘RoadDisplayWithTraffic’ 클래스를 만들어야 된다. 또한 ‘기본 도로 표시+차선 표시+교통량 표시’를 하려면 ‘RoadDisplayWithLaneAndTraffic’ 클래스를 만들어야 된다.
해결책: 데코레이터 객체를 사용한다. 데코레이터는 기본 기능(Original)을 데코레이션할 수도 있고, 또 다른 데이코레이터를 데코레이션할 수도 있다.
Decorator 객체의 draw() 메소드는 슈퍼 클래스의 draw() 메소드를 먼저 호출하는 구조를 지닌다.
ex) LaneDecorator의 draw()는 DisplayDecorator의 draw()를 호출함으로써 RoadDisplay의 draw() 기능을 처리한 뒤 자신의 기능을 수행한다.
abstract class Display{ public abstract void draw(); } class RoadDisplay extends Display{ public void draw() { System.out.println("기본 도로 표시"); } } // 다양한 추가 기능에 대한 공통 클래스 abstract class DisplayDecorator extends Display{ private Display decoratedDisplay; public DisplayDecorator(Display decoratedDisplay) { this.decoratedDisplay = decoratedDisplay; } public void draw() { decoratedDisplay.draw(); } } class LaneDecorator extends DisplayDecorator{ public LaneDecorator(Display decoratedDisplay) { super(decoratedDisplay); } public void draw() { super.draw(); // 설정된 기존 표시 기능을 수행 drawLane(); // 추가적으로 차선을 표시 } private void drawLane() { System.out.println("\t차선 표시"); } } class TrafficDecorator extends DisplayDecorator{ public TrafficDecorator(Display decoratedDisplay) { super(decoratedDisplay); } public void draw() { super.draw(); drawTraffic(); } private void drawTraffic() { System.out.println("\t교통량 표시"); } } public class Client{ public static void main(String[] args) { Display road=new RoadDisplay(); road.draw(); Display roadWithLane=new LaneDecorator(new RoadDisplay()); roadWithLane.draw(); Display roadWithTraffic=new TrafficDecorator(new RoadDisplay()); roadWithTraffic.draw(); } }