728x90
반응형
데코레이터 패턴(decorator)
객체의 결합을 통해 기능을 동적으로 유연하게 확장할 수 있게 해주는 패턴
데코레이터 패턴 구조
역할
- Component
- 기본 기능을 뜻하는 ConcreteComponent와 추가 기능을 뜻하는 Decorator의 공통 기능을 정의
- 즉, 클라이언트는 Component를 통해 실제 객체를 사용함.
- ConcreteComponent
- 기본 기능을 구현하는 클래스
- Decorator
- 많은 수가 존재하는 구체적인 Decorator의 공통 기능을 제공
- ConcreteDecorator1, ConcreteDecorator2
- Decorator의 하위 클래스로 기본 기능에 추가되는 개별적인 기능을 뜻함.
- ConcreteDecorator 클래스는 ConcreteComponent 객체에 대한 참조가 필요한데, 이는 Decorator 클래스에서 Component 클래스에서 Componenet 클래스로의 '합성(composition) 관계'를 통해 표현됨.
데코레이터 패턴 특징
패턴 사용 시기
- 객체 책임과 행동이 동적으로 상황에 따라 다양한 기능이 빈번하게 추가/삭제되는 경우
- 객체의 결합을 통해 기능이 생성될 수 있는 경우
- 객체를 사용하는 코드를 손상시키지 않고, 런타임에 객체에 추가 동작을 할당할 수 있어야 하는 경우
- 상속을 통해 서브 클래싱으로 객체의 동작을 확장하는 것이 어색하거나 불가능할 때
패턴 장점
- 데코레이터를 사용하면 서브클래스를 만들때보다 훨씬 더 유연하게 기능을 확장할 수 있다.
- 객체를 여러 데코레이터로 래핑하여 여러 동작을 결합할 수 있다.
- 컴파일 타임이 아닌 런타임에 동적으로 기능을 변경할 수 있다.
- 각 장식자 클래스마다 고유의 책임을 가져 단일 책임 원칙(SRP)
- 클라이언트 코드 수정 없이 기능 확장이 필요하면 장식자 클래스를 추가하면 되니 개방 폐쇄 원칙(OCP)
- 구현체가 아닌 인터페이스를 바라봄으로써 의존 역전 원칙(DIP)
패턴 단점
- 만일 장식자 일부를 제거하고 싶다면, Wrapper 스택에서 특정 wrapper를 제거하는 것은 어렵다.
- 데코레이터를 조합하는 초기 생성코드가 보기 안좋을 수 있다. ex) new A(new B(new C(new D())))
- 어느 장식자를 먼저 데코레이팅 하느냐에 따라 데코레이터 스택 순서가 결정되게 되는데, 만일 순서에 의해 의존하지 않는 방식으로 데코레이터를 구현하기는 어렵다.
활용 예시) 도료 표시 방법 조합
1) 데코레이터 패턴 X
// 기본 도로 표시 클래스
public class RoadDisplay {
public void draw() { System.out.println("기본 도로 표시"); }
}
// 기본 도로 표시 + 차선 표시 클래스
public class RoadDisplayWithLane extends RoadDisplay {
public void draw() {
super.draw(); // 상위 클래스, 즉 RoadDisplay 클래스의 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(); // 기본 도로 표시 + 차선 표시
}
1-1) 문제점
1. 다른 도로 표시 기능을 추가로 구현하는 경우 (+ 교통량 표시 기능)
// 기본 도로 표시 + 교통량 표시 클래스
public class RoadDisplayWithTraffic extends RoadDisplay {
public void draw() {
super.draw(); // 상위 클래스, 즉 RoadDisplay 클래스의 draw 메서드를 호출해서 기본 도로 표시
drawTraffic(); // 추가적으로 교통량 표시
}
private void drawTraffic() { System.out.println("교통량 표시"); }
}
2. 여러 가지 추가 기능을 조합해야 하는 경우
=> 상속을 통한 기능의 확장은 각 기능별로 클래스를 추가해야 한다. => 중복 발생
데코레이터 패턴 O
각 기능별로 개별적인 클래스를 설계하고, 기능을 조합할 때, 각 클래스의 객체 조합을 이용
public abstract class Display {
public abstract void draw();
}
/* 기본 도로 표시 클래스 */
public class RoadDisplay extends Display {
@Override
public void draw() { System.out.println("기본 도로 표시"); }
}
/* 다양한 추가 기능에 대한 공통 클래스 */
public abstract class DisplayDecorator extends Display {
private Display decoratedDisplay;
// '합성(composition) 관계'를 통해 RoadDisplay 객체에 대한 참조
public DisplayDecorator(Display decoratedDisplay) {
this.decoratedDisplay = decoratedDisplay;
}
@Override
public void draw() { decoratedDisplay.draw(); }
}
/* 차선 표시를 추가하는 클래스 */
public class LaneDecorator extends DisplayDecorator {
// 기존 표시 클래스의 설정
public LaneDecorator(Display decoratedDisplay) { super(decoratedDisplay); }
@Override
public void draw() {
super.draw(); // 설정된 기존 표시 기능을 수행
drawLane(); // 추가적으로 차선을 표시
}
// 차선 표시 기능만 직접 제공
private void drawLane() { System.out.println("\t차선 표시"); }
}
/* 교통량 표시를 추가하는 클래스 */
public class TrafficDecorator extends DisplayDecorator {
// 기존 표시 클래스의 설정
public TrafficDecorator(Display decoratedDisplay) { super(decoratedDisplay); }
@Override
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(); // 기본 도로 표시 + 교통량 표시
}
}
& 참고자료
https://gmlwjd9405.github.io/2018/07/09/decorator-pattern.html
[Design Pattern] 데코레이터 패턴이란 - Heee's Development Blog
Step by step goes a long way.
gmlwjd9405.github.io
https://inpa.tistory.com/entry/GOF-💠-데코레이터Decorator-패턴-제대로-배워보자
💠 데코레이터(Decorator) 패턴 - 완벽 마스터하기
Decorator Pattern 데코레이터 패턴(Decorator Pattern)은 대상 객체에 대한 기능 확장이나 변경이 필요할때 객체의 결합을 통해 서브클래싱 대신 쓸수 있는 유연한 대안 구조 패턴이다. Decorator을 해석하
inpa.tistory.com
728x90
반응형
'CS > 디자인패턴' 카테고리의 다른 글
디자인 패턴 - 싱글톤 패턴, 팩토리 패턴, 전략 패턴 (0) | 2025.04.01 |
---|