디자인 패턴 – 데코레이터 패턴

데코레이터 패턴: 기본 기능에 옵션을 추가하는 경우 유용한 패턴

기존 코드: 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();
	}
}

Leave a Reply

Your email address will not be published. Required fields are marked *