의도
- 객체에 추가적인 책임을 동적으로 부여합니다. 데코레이터는 기능 확장을 위해 서브 클래스에 대한 유연한 대안을 제공합니다.
- 핵심 오브젝트를 클라이언트가 재귀적으로 랩핑하여 꾸미는 것
- 즉, 선물 포장, 상자에 넣고 상자를 포장합니다.
문제
런타임에 개별 객체에 동작 또는 상태를 추가하려고합니다. 정적이며 전체 클래스에 적용되므로 상속은 불가능합니다.
논의
사용자 인터페이스 툴킷에서 작업 중이고 창에 테두리 및 스크롤 막대 추가를 지원한다고 가정하십시오. 상속 계층 구조를 다음과 같이 정의 할 수 있습니다.
그러나 데코레이터 패턴은 고객에게 원하는 "기능" 조합을 지정할 수있는 기능을 제공합니다.
Widget* aWidget = new BorderDecorator(
new HorizontalScrollBarDecorator(
new VerticalScrollBarDecorator(
new Window( 80, 24 ))));
aWidget->draw();
이 유연성은 다음과 같은 디자인으로 달성 할 수 있습니다
커스텀 객체를 생성하기 위한 캐스케이딩 (또는 연쇄) 기능의 또 다른 예는 다음과 같습니다.
Stream* aStream = new CompressingStream(
new ASCII7Stream(
new FileStream("fileName.dat")));
aStream->putString( "Hello world" );
이 클래스의 문제점에 대한 솔루션은 추상 랩퍼 인터페이스 내에 원래 오브젝트를 캡슐화하는 것입니다. 데코레이터 객체와 코어 객체는 모두 이 추상 인터페이스에서 상속됩니다. 이 인터페이스는 재귀적 구성을 사용하여 각 코어 객체에 무제한의 데코레이터 "레이어"를 추가 할 수 있습니다.
이 패턴을 사용하면 객체의 인터페이스에 대한 메소드가 아니라 객체에 책임을 추가 할 수 있습니다. 클라이언트에 제공되는 인터페이스는 연속 레이어가 지정될 때 일정하게 유지되어야합니다.
또한 핵심 오브젝트의 ID가 이제 데코레이터 오브젝트 내부에 "숨겨져"있습니다. 문제는 핵심 객체에 직접 액세스하는 것입니다.
구조
클라이언트는 항상 CoreFunctionality.doThis ()에 관심이 있습니다. 클라이언트는 OptionalOne.doThis() 및 OptionalTwo.doThis()에 관심이 있거나 없을 수 있습니다. 이러한 각 클래스는 항상 Decorator 기본 클래스에 위임되며 해당 클래스는 항상 포함 된 "wrapper" 객체에 위임됩니다.
예시
데코레이터는 객체에 동적으로 추가 책임을 부여합니다. 소나무 또는 전나무에 추가되는 장식품은 데코레이터가 바로 그 예입니다. 조명, 화환, 사탕 지팡이, 유리 장식품 등을 나무에 추가하여 축제 분위기를 연출할 수 있습니다. 장식품은 사용된 특정 장식품에 관계없이 크리스마스 트리로 인식 할 수 있는 트리 자체를 변경하지 않습니다. 추가 기능의 예로 조명을 추가하면 크리스마스 트리를 "조명화" 할 수 있습니다.
또 다른 예 : 돌격 총은 그 자체로 치명적인 무기입니다. 그러나 특정 "장식"을 적용하면 더 정확하고 조용하며 파괴적입니다.
점검리스트
- 컨텍스트가 단일 코어 (또는 비선택적) 구성 요소, 여러 가지 선택적인 장식 또는 랩퍼 및 모두에게 공통적인 인터페이스인지 확인해야 합니다.
- 모든 클래스를 상호 교환 할 수 있는 "최소 공통 분모" 인터페이스를 작성해야 합니다.
- 선택적 랩퍼 클래스를 지원하기 위해 두 번째 레벨 기본 클래스 (Decorator)를 작성해야 합니다.
- Core 클래스와 Decorator 클래스는 LCD 인터페이스에서 상속됩니다.
- Decorator 클래스는 LCD 인터페이스에 컴포지션 관계를 선언하고 이 데이터 멤버는 생성자에서 초기화됩니다.
- Decorator 클래스는 LCD 객체에 위임합니다.
- 각 선택적 꾸미기에 대해 Decorator 파생 클래스를 정의하십시오.
- Decorator 파생 클래스는 래퍼 기능을 구현하고 Decorator 기본 클래스에 위임합니다.
- 클라이언트는 Core 및 Decorator 객체의 유형과 순서를 구성합니다.
주요 규칙
- 어댑터는 Subject와 다른 인터페이스를 제공합니다. 프록시는 동일한 인터페이스를 제공합니다. Decorator는 향상된 인터페이스를 제공합니다.
- 어댑터는 객체의 인터페이스를 변경하고 Decorator는 객체의 책임을 향상시킵니다. 따라서 데코레이터는 클라이언트에게 더 투명합니다. 결과적으로, Decorator는 순수한 어댑터로는 불가능한 재귀적 구성을 지원합니다.
- Composite과 Decorator는 유사한 구조 다이어그램을 가지고 있으며, 둘 다 재귀 구성에 의존하여 개방형의 객체를 구성한다는 사실을 반영합니다.
- 데코레이터는 하나의 구성 요소만 있는 Composite로 볼 수 있습니다. 그러나 데코레이터는 추가 책임을 추가합니다. 객체 집계를 위한 것이 아닙니다.
- Decorator는 서브 클래스 없이 객체에 책임을 추가 할 수 있도록 설계되었습니다. Composite의 초점은 꾸밈이 아니라 표현에 있습니다. 이러한 의도는 별개이지만 보완적입니다. 결과적으로 컴포지트 및 데코레이터는 종종 사용됩니다.
- Composite은 책임 체인을 사용하여 구성 요소가 부모를 통해 전역 속성에 액세스 할 수 있도록 합니다. 또한 Decorator를 사용하여 컴포지션의 일부에서 이러한 속성을 재정의 할 수 있습니다.
- 데코레이터와 프록시는 목적이 다르지만 구조는 비슷합니다. 둘 다 다른 객체에 대한 간접적인 수준을 제공하는 방법을 설명하고 구현은 요청을 전달하는 객체에 대한 참조를 유지합니다.
- 데코레이터를 사용하면 오브젝트의 스킨을 변경할 수 있습니다. Strategy를 사용하면 내장을 변경할 수 있습니다.
'SW > 디자인 패턴' 카테고리의 다른 글
싱글턴 디자인 패턴 : 정의, 개념, 구조 예시 (0) | 2019.10.05 |
---|---|
옵저버 디자인 패턴 : 정의, 구조, 개념은 무엇일까? (0) | 2019.09.08 |
디자인 패턴 : 스트래티지 디자인 패턴 : 정의, 구조, 예시 (0) | 2019.03.31 |
디자인 패턴 : 장점, 중요한 이유 (0) | 2019.03.30 |
디자인 패턴 : 정의, 범주 (0) | 2019.03.30 |