Priv's Blog
10. 데커레이터 패턴 본문
1. 도로 표시 방법 조회하기
내비게이션에서 도로를 표시하는 기능을 가정하자.
기본적인 기능은 도로를 선으로 표시하는 것이겠지만, 내비게이션의 종류마다 차선을 표시해주기도 한다.
즉, 차선 표시 기능은 핵심/기본 기능이 아니라 추가 기능이다.
RoadDisplay 클래스는 핵심/기본 기능인 도로를 표시하는 기능을 담당한다.
RoadDisplayWithLane 클래스는 차선을 표시하는 추가 기능을 담당한다.
여기서 RoadDisplayWithLane 클래스 역시 도로를 표시하므로, RoadDisplay 클래스의 하위 클래스에 해당한다.
package P10;
public class RoadDisplay {
public void Draw() {
System.out.println("기본 도로 표시");
}
}
package P10;
public class RoadDisplayWithLane extends RoadDisplay {
public void Draw() {
super.Draw();
DrawLine();
}
private void DrawLine() {
System.out.println("차선 표시");
}
}
RoadDisplayWithLane클래스에서 기본 도로 표시 기능은 상위 클래스를 통해 구현하고, 차선 표시 기능은 drawLane 메서드로 구현한다.
2. 문제점
또 다른 도로 표시 기능을 추가로 구현하고 싶다면?
여러 추가 기능을 조합해 제공하고 싶다면?
2.1) 또 다른 도로 표시 기능을 추가할 경우
RoadDisplayWithLane 클래스처럼 새로운 클래스를 정의하여 RoadDisplay의 자식 클래스로 만들면 된다.
package P10;
public class RoadDisplay {
public void Draw() {
System.out.println("기본 도로 표시");
}
}
package P10;
public class RoadDisplayWithTraffic extends RoadDisplay {
public void Draw() {
super.Draw();
DrawTraffic();
}
private void DrawTraffic() {
System.out.println("교통량 표시");
}
}
package P10;
public class RoadDisplayWithLane extends RoadDisplay {
public void Draw() {
super.Draw();
DrawLine();
}
private void DrawLine() {
System.out.println("차선 표시");
}
}
2.2) 여러 추가 기능을 조합해야 하는 경우
다양한 기능의 조합을 고려해야 하는 경우, 상속을 통한 기능 확장은 각 기능별로 클래스를 추가해야 한다는 단점이 있다.
즉, 차선, 교통량, 교차로 등 다양한 기능을 추가로 제공할 경우, 그 모든 경우에 수에 따른 클래스를 만들어야 한다는 것이다.
이 모든 클래스를 구현하는 것은 너무 비효율적이고 복잡한 방식이다.
3. 해결책
상속을 이용하는 방법을 사용하기에는 경우의 수가 기하급수적으로 늘어날 수 있다는 문제점이 존재한다.
이를 해결하기 위해서는 각 추가 기능별로 개별적인 클래스를 설계하고, 기능을 조합할 때 각 클래스의 객체 조합을 사용하면 된다.
즉, 필요에 따라 단일 기능을 제공하는 클래스 여러 개를 합쳐서 복수 기능을 구현하는 것이다.
package P10;
public abstract class Display {
public abstract void Draw();
}
package P10;
public class RoadDisplay extends Display {
public void Draw() {
System.out.println("기본 도로 표시");
}
}
package P10;
public class DisplayDecorator extends Display {
private Display decorDisplay;
public DisplayDecorator(Display decorDisplay) {
this.decorDisplay = decorDisplay;
}
public void Draw() {
decorDisplay.Draw();
}
}
package P10;
public class LaneDecorator extends DisplayDecorator {
public LaneDecorator(Display decorDisplay) {
super(decorDisplay);
}
public void Draw() {
super.Draw();
DrawLine();
}
private void DrawLine() {
System.out.println("차선 표시");
}
}
package P10;
public class TrafficDecorator extends DisplayDecorator {
public TrafficDecorator(DisplayDecorator decorDisplay) {
super(decorDisplay);
}
public void Draw() {
super.Draw();
DrawTraffic();
}
private void DrawTraffic() {
System.out.println("교통량 표시");
}
}
만약 여기에 교차로를 표시하는 추가 기능을 구현하면서 기존의 다른 추가 기능과의 조합을 지원하려면 다음과 같이 구현하면 된다.
4. 데커레이터 패턴
데커레이터 패턴은 기본 기능에 추가할 수 있는 다양한 기능들이 존재할 경우, 각 추가 기능들을 Decorator 클래스로 정의한 후, 필요한 Decorator 객체를 조합함으로써 추가 기능의 조합을 설계하는 패턴이다.
기본 도로 표시 기능, 차선 표시, 교통량 표시, 단속 카메라 표시까지 총 추가 기능이 4가지가 있을 때 모든 조합은 15가지나 된다.
이때 데커레이터 패턴을 사용하면 개별 추가 기능에 해당하는 Decorator 4개를 구현하고, 개별 추가 기능을 필요에 따라 객체 형태로 조합하면 된다.
즉, 데커레이터 패턴은 기본 기능에 추가할 수 있는 많은 종류의 부가 기능에서 파생되는 다양한 조합을 동적으로 구현할 수 있는 패턴이다.
데커레이터 패턴을 도로 표시 예제에 적용하면 다음과 같다.
수고하셨습니다!
'Dev. Study Note > Design Pattern' 카테고리의 다른 글
12. 팩토리 메서드 패턴 (0) | 2022.07.03 |
---|---|
11. 템플릿 메서드 패턴 (0) | 2022.07.03 |
9. 옵서버 패턴 (0) | 2022.07.03 |
8. 커맨드 패턴 (0) | 2022.07.03 |
7. 스테이트 패턴 (0) | 2022.07.03 |