장식자 패턴
Decorator pattern![]() |
객체 지향 프로그래밍에서, 장식자 패턴은 동일한 클래스의 다른 객체의 동작에 영향을 주지 않고, 역동적으로 개별 객체에 동작을 추가할 수 있도록 하는 디자인 패턴이다.[1]실내 장식자 패턴은 종종 단일 책임 원칙을 준수하는데 유용하다. 왜냐하면 그것은 기능성을 고유한 관심 영역을 가진 계층 간에 나눌 수 있기 때문이다.[2]완전히 새로운 물체를 정의하지 않고도 물체의 행동을 증강시킬 수 있기 때문에 장식자 사용은 하위 분류보다 더 효율적일 수 있다.
개요
장식가[3] 설계 패턴은 23개의 잘 알려진 GoF 설계 패턴 중 하나로, 반복적인 설계 문제를 해결하고 유연하고 재사용 가능한 객체 지향 소프트웨어(즉, 구현, 변경, 테스트 및 재사용하기 쉬운 객체)를 설계하는 방법을 설명한다.
어떤 문제를 해결할 수 있을까?
- 런타임에 동적으로 개체에 책임을 추가(제거)해야 한다.[4]
- 기능 확장을 위한 하위 분류에 대한 유연한 대안이 제공되어야 한다.
서브클래싱을 사용할 때, 다른 서브클래스는 다른 방식으로 클래스를 확장한다.그러나 확장자는 컴파일 시간에 클래스에 바인딩되어 런타임에는 변경할 수 없다.[citation needed]
어떤 솔루션을 설명하고 있는가?
정의Decorator
하는 사물.
- 확장(확장) 객체의 인터페이스를 구현한다.
Component
)모든 요청을 해당 요청에 전달하여 투명하게 처리 - 요청을 전달하기 전/후에 추가 기능을 수행한다.
이를 통해 다양한 작업 가능Decorator
런타임에 객체의 기능을 동적으로 확장하는 객체.
아래 UML 클래스 및 시퀀스 다이어그램을 참조하십시오.
의도

설계 시 기초 작업을 수행할 경우, 특정 물체의 기능을 정적으로 확장(결정)하거나, 같은 등급의 다른 경우와 독립적으로 런타임에 확장(결정)하는 데 데 데 데코레이터 패턴을 사용할 수 있다.이것은 원래 클래스를 감싸는 새로운 Decorator 클래스를 설계함으로써 달성된다.이 포장은 다음과 같은 단계를 통해 달성할 수 있다.
- 원래 구성 요소 클래스를 Decorator 클래스로 하위 분류(UML 다이어그램 참조);
- Decorator 클래스에서 구성 요소 포인터를 필드로 추가하십시오.
- Decorator 클래스에서 구성 요소를 Decorator 생성자에게 전달하여 구성 요소 포인터를 초기화하십시오.
- Decorator 클래스에서 모든 구성 요소 방법을 구성 요소 포인터로 전달하십시오.
- ConcreteDecorator 클래스에서 동작을 수정해야 하는 모든 구성 요소 메서드를 재정의하십시오.
이 패턴은 다중 장식자가 서로 위로 쌓일 수 있도록 설계되었으며, 매번 오버라이드 방식에 새로운 기능을 추가한다.
장식가와 원래 클래스 객체는 공통 피쳐 집합을 공유한다는 점에 유의하십시오.앞의 도표에서는 조작() 방법을 장식과 미장식 모두 사용할 수 있었다.
장식 특징(예: 방법, 속성 또는 기타 구성원)은 일반적으로 인터페이스, 믹신(예: 특성) 또는 클래스 상속(예: 장식된 개체)에 의해 정의되며, 장식된 개체와 함께 공유된다.앞의 예에서 구성 요소 클래스는 DescentComponent와 Decorator에서 내려오는 하위 클래스에 의해 상속된다.
실내 장식 패턴은 하위 클래스의 대안이다.서브클래싱은 컴파일 시간에 동작을 추가하며, 변경사항은 원본 클래스의 모든 인스턴스에 영향을 미친다. 장식은 선택된 객체에 대해 런타임에 새로운 동작을 제공할 수 있다.
이러한 차이는 기능성을 확장하는 몇 가지 독립적인 방법이 있을 때 가장 중요하게 된다.일부 객체 지향 프로그래밍 언어에서 클래스는 런타임에 생성될 수 없으며, 일반적으로 설계 시 확장자의 어떤 조합이 필요할지를 예측할 수 없다.이것은 가능한 모든 조합에 대해 새로운 클래스가 만들어져야 한다는 것을 의미할 것이다.이와는 대조적으로, 장식가는 객체로서, 런타임에 만들어지며, 사용당 기준으로 결합될 수 있다.Java 및 의 I/O 스트림 구현.NET Framework는 장식자 패턴을 통합한다.
동기
예를 들어 윈도우 시스템의 윈도우를 생각해 보십시오.창 내용의 스크롤을 허용하려면, 적절한 경우 창 내용에 수평 또는 수직 스크롤 막대를 추가해야 할 수 있다.윈도우가 윈도우 인터페이스의 인스턴스로 표현된다고 가정하고, 이 클래스가 스크롤바를 추가하는 기능이 없다고 가정한다.이러한 기능을 제공하는 하위 클래스 ScrollingWindow를 만들거나 기존 Window 개체에 이 기능을 추가하는 ScrollingWindowDecorator를 만들 수 있다.이 시점에서는 어느 쪽이든 괜찮다.
자, 창문에 테두리를 추가할 수 있는 능력도 원한다고 가정합시다.다시 말하지만, 원래의 윈도우 클래스는 지원이 없다.ScrollingWindow 하위 클래스는 효과적으로 새로운 종류의 창을 만들었기 때문에 현재 문제가 되고 있다.모든 창에 국경 지원을 추가하려면 WindowWithBorder 및 ScrollingWindowWithWord 등의 하위 클래스를 만들어야 한다.이 문제는 추가될 모든 새로운 기능 또는 창 하위 유형으로 인해 악화된다.장식기 솔루션을 위해 새로운 WinderWindowDecorator가 생성된다.ScrollingWindowDecorator 또는 FoundedWindowDecorator의 모든 조합은 기존 창을 장식할 수 있다.기능을 모든 Windows에 추가해야 하는 경우 기본 클래스를 수정할 수 있다.한편, 때로는 (예를 들어, 외부 프레임워크를 사용하는 것) 베이스 클래스를 수정하는 것이 가능하지 않거나, 합법적이거나, 편리하지 않을 때도 있다.
앞의 예에서 SimpleWindow 및 WindowDecorator 클래스는 창 컨트롤을 장식하기 위해 이 시나리오에 필요한 그리기() 방법과 getDescription() 방법을 정의하는 윈도우 인터페이스를 구현한다.
일반 사용 사례
장식가 적용
명령어에 장식가를 추가하거나 제거하는 것은 일반적인 UI 패턴으로, 명령 설계 패턴과 함께 종종 구현된다.예를 들어, 텍스트 편집 응용 프로그램에는 텍스트를 강조 표시하는 버튼이 있을 수 있다.버튼을 누르면 현재 선택된 개별 텍스트 글리프는 모두 추첨() 함수를 수정하는 장식기로 포장되어 강조 표시된 방식으로 그리게 된다(실제 구현은 효율을 극대화하기 위해 경계 시스템을 사용하기도 한다).
상태 변화에 따라 장식가를 적용하거나 제거하는 것도 일반적인 사용 사례다.국가의 범위에 따라 실내장식을 대량으로 적용하거나 제거할 수 있다.마찬가지로, 상태 설계 패턴은 변화하는 기능성을 캡슐화하는 하위 분류 객체 대신 장식기를 사용하여 구현될 수 있다.이러한 방식으로 장식자를 사용하면 상태 객체의 내부 상태와 기능이 보다 구성적이고 임의의 복잡성을 처리할 수 있게 된다.
Flyweight 객체의 사용
장식은 플라이급 디자인 패턴에도 자주 사용된다.플라이급 객체는 모든 플라이급 객체 간에 공유되는 불변성 구성 요소와 부분적으로 공유되거나 완전히 비공유될 수 있는 변형, 장식된 구성 요소의 두 가지 요소로 나뉜다.이 플라이급 객체의 분할은 메모리 소비를 줄이기 위한 것이다.장식가들도 일반적으로 캐시되고 재사용된다.장식가들은 모두 공유되고 불변하는 대상에 대한 공통적인 참조를 포함할 것이다.장식된 상태가 부분적으로만 변형된 경우, 장식가보다 어느 정도 더 공유될 수 있다. 단, 사용하는 동안 상태를 변경하지 않도록 주의해야 한다.iOS의 UITableView는 이러한 방식으로 플라이급 패턴을 구현한다 - 테이블뷰의 재사용 가능한 셀은 일반적인 테이블뷰 행 객체에 대한 참조를 포함하는 장식가로서, 셀은 캐시/재사용된다.
장식가와의 인터페이스의 장애물
여러 가지 방법으로 장식가들의 조합을 오브젝트 모음에 적용하면, 장식가가 추가한 기능을 최대한 활용하는 방식으로 컬렉션과 인터페이스하는 몇 가지 문제가 발생한다.어댑터 또는 방문자 패턴의 사용은 이러한 경우에 유용할 수 있다.여러 층의 장식가와의 인터페이스는 추가적인 도전을 제기하며 어댑터와 방문객의 논리는 이를 감안하도록 설계되어야 한다.
건축 관련성
장식가들은 기능성을 확장하기 위해 오히려 하향식, 계층적 접근방식을 지원한다.실내 장식자는 런타임에 인터페이스의 동작을 추가하거나 변경할 수 있도록 한다.그것들은 다층적이고 임의적인 방법들의 조합으로 물체를 포장하는데 사용될 수 있다.하위 클래스와 동일한 작업을 한다는 것은 다중 상속의 복잡한 네트워크를 구현하는 것을 의미하는데, 이것은 기억력이 떨어지고 특정 시점에서 확장될 수 없다.마찬가지로, 속성으로 동일한 기능을 구현하려고 시도하면 불필요한 속성으로 개체의 각 인스턴스가 부풀어 오른다.위의 이유로 장식가들은 종종 하위 분류에 대한 기억 효율적인 대안으로 간주된다.
실내 장식자는 하위 분류가 불가능한 객체, 런타임에 특성을 변경해야 하는 객체 또는 필요한 기능성이 결여된 일반적으로 객체를 전문화하는 데 사용될 수도 있다.
API 향상을 위한 사용법
장식자 패턴은 또한 파사드 패턴을 증가시킬 수 있다.파사드는 캡슐화된 복잡한 시스템과 간단히 인터페이스하도록 설계되었지만, 시스템에 기능을 추가하지는 않는다.그러나 복잡한 시스템의 포장은 시스템의 하위 구성 요소의 조정에 기초하여 새로운 기능성을 도입하는 데 사용될 수 있는 공간을 제공한다.예를 들어, 전면 패턴은 하나의 다국어 사전 인터페이스로 많은 다른 언어 사전을 통합할 수 있다.또한 새로운 인터페이스는 언어간 단어 번역에 새로운 기능을 제공할 수 있다.이것은 하이브리드 패턴이다 - 통합 인터페이스는 증강을 위한 공간을 제공한다.장식가들이 개별적인 물체를 감싸는 것에만 국한되지 않고, 이 하이브리드 접근방식에서도 물체의 군집을 감싸는 능력이 있다고 생각해 보십시오.
장식가의 대안
장식자 패턴의 대안으로, 래퍼가 특정 인터페이스를 존중해야 하고 다형성 동작을 지원해야 할 때 어댑터를 사용할 수 있으며, 기초적인 물체에 대한 더 쉽고 단순한 인터페이스를 원할 때 Facade를 사용할 수 있다.[5]
패턴 | 의도 |
---|---|
어댑터 | 클라이언트가 기대하는 것과 일치하도록 한 인터페이스를 다른 인터페이스로 변환 |
장식가 | 원래 코드를 감싸 인터페이스에 동적으로 책임감 추가 |
파사드 | 간소화된 인터페이스 제공 |
구조
UML 클래스 및 시퀀스 다이어그램

위의 UMLclass 다이어그램에서, 추상적 도표Decorator
클래스는 참조를 유지한다(component
장식된 물건에 ( )Component
() 및 모든 요청을 이 문서에 전달)component.operation()
). 이렇게 하면 된다.Decorator
의 고객에게 투명(불투명)Component
.
하위 클래스:Decorator1
,Decorator2
) 추가 동작 구현(addBehavior()
에 추가되어야 하는Component
(요청을 전달하기 전/후).
시퀀스 다이어그램은 런타임 교호작용을 보여준다.그Client
사물이 통하다.Decorator1
그리고Decorator2
의 기능을 확장하는 개체Component1
이의를 제기하다
그Client
전화를 하다operation()
에 관하여Decorator1
에 요청을 전달한다.Decorator2
.Decorator2
공연하다addBehavior()
요청을 에 전달한 후.Component1
로 돌아가다.Decorator1
, 수행.addBehavior()
그리고 다시 로 돌아오다.Client
.
예
가다
꾸러미 해독의 수입하다 ( "로그" "시간" ) //OperateFn은 장식이 필요한 작업을 나타냄 타자를 치다 오퍼레이션Fn 펑크() //작전의 의욕 펑크 꾸미다(opFn 오퍼레이션Fn) { 연기하다 펑크(s 시간.시간) { 통나무를 하다.프린트프("오류 시간 %0.2dms, 시간.이후(s).나노세컨드() / 1000000) }(시간.지금()) // 실제 작동 기능 opFn() } // 패키지 메인 꾸러미 본래의 수입하다 ( "github.com/tkstorm/go-design/structural/decorator/decolog" "로그" "산술/랜드" "시간" ) //출력: //2019/08/19 19:05:24 종료 조치 a //2019/08/19 19:05:24 경과 시간 77ms //2019/08/19 19:05:24 종료 조치 b //2019/08/19 19:05:24 경과 시간 88ms 펑크 본래의() { // 로그 a를 꾸미다 해독의.꾸미다(해독의.오퍼레이션Fn(도액션a)) // 로그 b를 꾸미다 해독의.꾸미다(해독의.오퍼레이션Fn(도액션B)) } 펑크 도액션a() { 시간.잠(시간.기간(랜드.intn(200)) * 시간.밀리초) 통나무를 하다.프린틀른("동작 a") } 펑크 도액션B() { 시간.잠(시간.기간(랜드.intn(200)) * 시간.밀리초) 통나무를 하다.프린틀른("동작 B") }
C++
여기에는 두 가지 옵션이 제시된다. 첫째, 동적 런타임 복합 장식가(명시적으로 대리하지 않는 한 장식된 기능을 호출하는 데 문제가 있음)와 혼합 상속 방식을 사용하는 장식가.
다이나믹 데코레이터
#include <아이오스트림> #include <끈> 구조상의 모양 { 가상의 ~모양() = 체납; 가상의 찌꺼기::끈을 매다 GetName() 경시하다 = 0; }; 구조상의 원 : 모양 { 공허하게 하다 크기 조정(둥둥 뜨다 요소) { 반지름 *= 요소; } 찌꺼기::끈을 매다 GetName() 경시하다 무효로 하다 { 돌아오다 찌꺼기::끈을 매다("반경 원") + 찌꺼기::to_string(반지름); } 둥둥 뜨다 반지름 = 10.0f; }; 구조상의 컬러 셰이프 : 모양 { 컬러 셰이프(경시하다 찌꺼기::끈을 매다& 색을 칠하다, 모양* 모양을 내다) : 색을 칠하다(색을 칠하다), 모양을 내다(모양을 내다) {} 찌꺼기::끈을 매다 GetName() 경시하다 무효로 하다 { 돌아오다 모양을 내다->GetName() + " 색칠된 " + 색을 칠하다; } 찌꺼기::끈을 매다 색을 칠하다; 모양* 모양을 내다; }; 인트로 본래의() { 원 원을 그리다; 컬러 셰이프 colored_messages("빨간색", &원을 그리다); 찌꺼기::뻐드렁니가 나다 << colored_messages.GetName() << 찌꺼기::끝을 맺다; }
#include <기억> #include <아이오스트림> #include <끈> 구조상의 웹 페이지 { 가상의 공허하게 하다 전시하다()=0; 가상의 ~웹 페이지() = 체납; }; 구조상의 기본 웹 페이지 : 웹 페이지 { 찌꺼기::끈을 매다 html; 공허하게 하다 전시하다() 무효로 하다 { 찌꺼기::뻐드렁니가 나다 << "기본 WEB 페이지" << 찌꺼기::끝을 맺다; } }; 구조상의 WebPageDecorator : 웹 페이지 { WebPageDecorator(찌꺼기::유니크_ptr<웹 페이지> 웹 페이지): _웹페이지(찌꺼기::움직이다(웹 페이지)) { } 공허하게 하다 전시하다() 무효로 하다 { _웹페이지->전시하다(); } 사유의: 찌꺼기::유니크_ptr<웹 페이지> _웹페이지; }; 구조상의 인증된 웹 페이지 : WebPageDecorator { 인증된 웹 페이지(찌꺼기::유니크_ptr<웹 페이지> 웹 페이지): WebPageDecorator(찌꺼기::움직이다(웹 페이지)) {} 공허하게 하다 인증사용자() { 찌꺼기::뻐드렁니가 나다 << "수정 완료" << 찌꺼기::끝을 맺다; } 공허하게 하다 전시하다() 무효로 하다 { 인증사용자(); WebPageDecorator::전시하다(); } }; 구조상의 AuthorizedWebPage : WebPageDecorator { AuthorizedWebPage(찌꺼기::유니크_ptr<웹 페이지> 웹 페이지): WebPageDecorator(찌꺼기::움직이다(웹 페이지)) {} 공허하게 하다 인증된 사용자() { 찌꺼기::뻐드렁니가 나다 << "완전 완료" << 찌꺼기::끝을 맺다; } 공허하게 하다 전시하다() 무효로 하다 { 인증된 사용자(); WebPageDecorator::전시하다(); } }; 인트로 본래의(인트로 argc, 마를 뜨다* 아그브[]) { 찌꺼기::유니크_ptr<웹 페이지> mypage = 찌꺼기::make_make<기본 웹 페이지>(); mypage = 찌꺼기::make_make<AuthorizedWebPage>(찌꺼기::움직이다(mypage)); mypage = 찌꺼기::make_make<인증된 웹 페이지>(찌꺼기::움직이다(mypage)); mypage->전시하다(); 찌꺼기::뻐드렁니가 나다 << 찌꺼기::끝을 맺다; 돌아오다 0; }
정적 장식기(믹신 상속)
이 예는 템플릿 인수에서 상속할 수 있는 C++ 능력 때문에 가능한 정적 Decorator 구현을 보여준다.
#include <아이오스트림> #include <끈> 구조상의 원 { 공허하게 하다 크기 조정(둥둥 뜨다 요소) { 반지름 *= 요소; } 찌꺼기::끈을 매다 GetName() 경시하다 { 돌아오다 찌꺼기::끈을 매다("반경 원") + 찌꺼기::to_string(반지름); } 둥둥 뜨다 반지름 = 10.0f; }; 템플릿 <타이프 이름 T> 구조상의 컬러 셰이프 : 공중의 T { 컬러 셰이프(경시하다 찌꺼기::끈을 매다& 색을 칠하다) : 색을 칠하다(색을 칠하다) {} 찌꺼기::끈을 매다 GetName() 경시하다 { 돌아오다 T::GetName() + " 색칠된 " + 색을 칠하다; } 찌꺼기::끈을 매다 색을 칠하다; }; 인트로 본래의() { 컬러 셰이프<원> 빨강_노랑("빨간색"); 찌꺼기::뻐드렁니가 나다 << 빨강_노랑.GetName() << 찌꺼기::끝을 맺다; 빨강_노랑.크기 조정(1.5f); 찌꺼기::뻐드렁니가 나다 << 빨강_노랑.GetName() << 찌꺼기::끝을 맺다; }
자바
첫 번째 예(창/스크롤링 시나리오)
다음 Java 예는 창/스크롤링 시나리오를 사용한 장식가의 사용을 예시한다.
// 윈도우 인터페이스 클래스 공중의 접점 창 { 공허하게 하다 그림그리다(); // 창 그리기 끈 getDescription(); // 창에 대한 설명 반환 } // 스크롤 막대 없이 간단한 창 구현 계급 심플윈도 기구들 창 { @오버라이드 공중의 공허하게 하다 그림그리다() { // 창 그리기 } @오버라이드 공중의 끈 getDescription() { 돌아오다 "슬라이드 윈도우"; } }
다음 수업은 모든 사람들을 위한 장식가들을 포함한다.Window
실내 장식가 수업 자체를 포함한 수업들
// 추상 장식가 클래스 - Window를 구현한다는 점에 유의 추상적 계급 윈도디코레이터 기구들 창 { 사유의 최종의 창 창ToBeDeorated; // 장식 중인 창 공중의 윈도디코레이터 (창 창ToBeDeorated) { 이.창ToBeDeorated = 창ToBeDeorated; } @오버라이드 공중의 공허하게 하다 그림그리다() { 창ToBeDeorated.그림그리다(); //위임 } @오버라이드 공중의 끈 getDescription() { 돌아오다 창ToBeDeorated.getDescription(); //위임 } } // 수직 스크롤바 기능을 추가한 최초의 콘크리트 장식기 계급 수직 ScrollBarDecorator 연장하다 윈도디코레이터 { 공중의 수직 ScrollBarDecorator (창 창ToBeDeorated) { 잘 하는 군요(창ToBeDeorated); } @오버라이드 공중의 공허하게 하다 그림그리다() { 잘 하는 군요.그림그리다(); 그림수직스크롤바(); } 사유의 공허하게 하다 그림수직스크롤바() { // 수직 스크롤 막대 그리기 } @오버라이드 공중의 끈 getDescription() { 돌아오다 잘 하는 군요.getDescription() + ", 세로 스크롤 막대 포함"; } } // 수평 스크롤 막대 기능을 추가하는 두 번째 콘크리트 장식기 계급 수평스크롤바디코레이터 연장하다 윈도디코레이터 { 공중의 수평스크롤바디코레이터 (창 창ToBeDeorated) { 잘 하는 군요(창ToBeDeorated); } @오버라이드 공중의 공허하게 하다 그림그리다() { 잘 하는 군요.그림그리다(); drawHorizontalScrollBar(); } 사유의 공허하게 하다 drawHorizontalScrollBar() { // 수평 스크롤 막대 그리기 } @오버라이드 공중의 끈 getDescription() { 돌아오다 잘 하는 군요.getDescription() + ", 수평 스크롤 막대 포함"; } }
여기 테스트 프로그램을 통해Window
완전히 장식된 예(예: 수직 및 수평 스크롤 막대) 및 그 설명을 인쇄하는 예:
공중의 계급 OrganizedWindowTest { 공중의 정태의 공허하게 하다 본래의(끈[] 아그) { // 가로 및 세로 스크롤 막대로 장식된 창 만들기 창 장식창 = 새로운 수평스크롤바디코레이터 ( 새로운 수직 ScrollBarDecorator (새로운 심플윈도())); // 창 설명 인쇄 시스템.밖으로.인쇄하다(장식창.getDescription()); } }
이 프로그램의 출력은 "수평 스크롤 바를 포함한 단순한 창"이다.어떻게 해야 하는지 주목하라.getDescription
두 실내 장식가의 방법은 먼저 장식된 것을 회수한다.Window
의 설명과 접미사로 그것을 장식하다
아래는 테스트 주도 개발을 위한 JUnit 테스트 클래스 입니다.
정적을 수입하다 org.junit주장.assertEquals; 수입하다 org.junit테스트; 공중의 계급 윈도디코레이터테스트 { @테스트 공중의 공허하게 하다 테스트창디코레이터테스트() { 창 장식창 = 새로운 수평스크롤바디코레이터(새로운 수직 ScrollBarDecorator(새로운 심플윈도())); // 설명에 실제로 수평 + 수직 스크롤 바가 포함되어 있다고 주장 어설픈 이퀄스("수직 스크롤 막대, 수평 스크롤 막대 포함", 장식창.getDescription()); } }
두 번째 예(커피 만들기 시나리오)
다음 자바 예는 커피메이킹 시나리오를 이용한 장식가의 사용을 예시한다.이 예에서 시나리오는 비용과 성분만 포함한다.
// Interface Coffee는 실내 장식가들에 의해 구현된 커피의 기능을 정의한다. 공중의 접점 커피 { 공중의 곱절로 하다 getcost(); // 커피 비용 반환 공중의 끈 Getingredients(); // 커피 성분 반환 } // 별도의 재료 없이 간단한 커피 연장 공중의 계급 심플커피 기구들 커피 { @오버라이드 공중의 곱절로 하다 getcost() { 돌아오다 1; } @오버라이드 공중의 끈 Getingredients() { 돌아오다 "커피"; } }
다음 수업은 모든 사람들을 위한 장식가들을 포함한다.실내 장식가 수업 자체를 포함한 커피 수업.
// 추상 장식가 클래스 - Coffee 인터페이스를 구현한다는 점에 유의 공중의 추상적 계급 커피디코레이터 기구들 커피 { 사유의 최종의 커피 장식코피; 공중의 커피디코레이터(커피 c) { 이.장식코피 = c; } @오버라이드 공중의 곱절로 하다 getcost() { // 인터페이스 방법 구현 돌아오다 장식코피.getcost(); } @오버라이드 공중의 끈 Getingredients() { 돌아오다 장식코피.Getingredients(); } } // 장식가 위드밀크는 우유를 커피에 섞는다. // CoffeeDecorator를 확장한다는 점에 유의하십시오. 계급 위드밀크 연장하다 커피디코레이터 { 공중의 위드밀크(커피 c) { 잘 하는 군요(c); } @오버라이드 공중의 곱절로 하다 getcost() { // 추상 슈퍼클래스에 정의된 메서드 재정의 돌아오다 잘 하는 군요.getcost() + 0.5; } @오버라이드 공중의 끈 Getingredients() { 돌아오다 잘 하는 군요.Getingredients() + ", 우유"; } } // 스프링클이 달린 장식기 커피에 스프링클을 섞는다. // CoffeeDecorator를 확장한다는 점에 유의하십시오. 계급 스프링클스 위드림 연장하다 커피디코레이터 { 공중의 스프링클스 위드림(커피 c) { 잘 하는 군요(c); } @오버라이드 공중의 곱절로 하다 getcost() { 돌아오다 잘 하는 군요.getcost() + 0.2; } @오버라이드 공중의 끈 Getingredients() { 돌아오다 잘 하는 군요.Getingredients() + ", 스프링클스"; } }
여기 완전히 꾸며진 커피 인스턴스(우유와 스프링클)를 만들어 커피 비용을 계산하고 그 성분을 인쇄하는 테스트 프로그램이 있다.
공중의 계급 메인 { 공중의 정태의 공허하게 하다 printInfo(커피 c) { 시스템.밖으로.인쇄하다("비용: " + c.getcost() + "; 재료: " + c.Getingredients()); } 공중의 정태의 공허하게 하다 본래의(끈[] 아그) { 커피 c = 새로운 심플커피(); printInfo(c); c = 새로운 위드밀크(c); printInfo(c); c = 새로운 스프링클스 위드림(c); printInfo(c); } }
이 프로그램의 출력은 다음과 같다.
비용: 1.0; 재료: 커피 비용: 1.5; 재료: 커피, 우유 비용: 1.7; 재료: 커피, 우유, 스프링클
PHP
추상적 계급 구성 요소 { 보호의 $data; 보호의 달러 가치; 추상적 공중의 기능을 발휘하다 getData(); 추상적 공중의 기능을 발휘하다 getValue(); } 계급 콘크리트 구성요소 연장하다 구성 요소 { 공중의 기능을 발휘하다 ____() { $ this->가치를 매기다 = 1000; $ this->자료 = "콘크리트 구성 요소:\t{$ this->가치를 매기다}\n"; } 공중의 기능을 발휘하다 getData() { 돌아오다 $ this->자료; } 공중의 기능을 발휘하다 getValue() { 돌아오다 $ this->가치를 매기다; } } 추상적 계급 장식가 연장하다 구성 요소 { } 계급 콘크리트디코레이터1 연장하다 장식가 { 공중의 기능을 발휘하다 ____(구성 요소 $data) { $ this->가치를 매기다 = 500; $ this->자료 = $data; } 공중의 기능을 발휘하다 getData() { 돌아오다 $ this->자료->getData() . "콘크리트 데코레이터 1:\t{$ this->가치를 매기다}\n"; } 공중의 기능을 발휘하다 getValue() { 돌아오다 $ this->가치를 매기다 + $ this->자료->getValue(); } } 계급 콘크리트디코레이터2 연장하다 장식가 { 공중의 기능을 발휘하다 ____(구성 요소 $data) { $ this->가치를 매기다 = 500; $ this->자료 = $data; } 공중의 기능을 발휘하다 getData() { 돌아오다 $ this->자료->getData() . "콘크리트 데코레이터 2:\t{$ this->가치를 매기다}\n"; } 공중의 기능을 발휘하다 getValue() { 돌아오다 $ this->가치를 매기다 + $ this->자료->getValue(); } } 계급 고객 { 사유의 $구성요소; 공중의 기능을 발휘하다 ____() { $ this->구성 요소 = 새로운 콘크리트 구성요소(); $ this->구성 요소 = $ this->랩구성 요소($ this->구성 요소); 메아리치다 $ this->구성 요소->getData(); 메아리치다 "클라이언트:\t\t\t"; 메아리치다 $ this->구성 요소->getValue(); } 사유의 기능을 발휘하다 랩구성 요소(구성 요소 $구성요소) { $componential1 = 새로운 콘크리트디코레이터1($구성요소); $구성요소2 = 새로운 콘크리트디코레이터2($componential1); 돌아오다 $구성요소2; } } $client = 새로운 고객(); // 결과: #quanton81 //콘크리트 성분: 1000 //콘크리트 장식기 1: 500 //콘크리트 장식기 2: 500 //클라이언트: 2000
파이톤
Python Wiki - DecoratorPattern에서 가져온 다음의 Python 예는 우리에게 어떤 물체에 많은 행동을 동적으로 추가하기 위해 장식가를 파이프라인하는 방법을 보여준다.
""" 0-255의 10x10 격자 그리드의 세계에서 실내 장식가 시연. """ 수입하다 무작위의 반항하다 s32_to_u16(x): 만일 x < 0: 서명하다 = 0xF000 다른: 서명하다 = 0 밑바닥의 = x & 0x00007FFF 돌아오다 밑바닥의 서명하다 반항하다 seed_from_xy(x, y): 돌아오다 s32_to_u16(x) (s32_to_u16(y) << 16) 계급 랜덤스퀘어: 반항하다 __init___(s, seed_properties): s.seed_properties = seed_properties 반항하다 얻다(s, x, y): 씨를 뿌리다 = seed_from_xy(x, y) ^ s.seed_properties 무작위의.씨를 뿌리다(씨를 뿌리다) 돌아오다 무작위의.랜딘트(0, 255) 계급 데이터제곱: 반항하다 __init___(s, initial_value=없음): s.자료 = [initial_value] * 10 * 10 반항하다 얻다(s, x, y): 돌아오다 s.자료[(y * 10) + x] # 예: 모두 10x10 입니다. 반항하다 세트(s, x, y, u): s.자료[(y * 10) + x] = u 계급 캐시디코레이터: 반항하다 __init___(s, 장식된): s.장식된 = 장식된 s.캐쉬 = 데이터제곱() 반항하다 얻다(s, x, y): 만일 s.캐쉬.얻다(x, y) == 없음: s.캐쉬.세트(x, y, s.장식된.얻다(x, y)) 돌아오다 s.캐쉬.얻다(x, y) 계급 맥스디코레이터: 반항하다 __init___(s, 장식된, 맥스.): s.장식된 = 장식된 s.맥스. = 맥스. 반항하다 얻다(s, x, y): 만일 s.장식된.얻다(x, y) > s.맥스.: 돌아오다 s.맥스. 돌아오다 s.장식된.얻다(x, y) 계급 민디코레이터: 반항하다 __init___(s, 장식된, 분): s.장식된 = 장식된 s.분 = 분 반항하다 얻다(s, x, y): 만일 s.장식된.얻다(x, y) < s.분: 돌아오다 s.분 돌아오다 s.장식된.얻다(x, y) 계급 VisibilityDecorator: 반항하다 __init___(s, 장식된): s.장식된 = 장식된 반항하다 얻다(s, x, y): 돌아오다 s.장식된.얻다(x, y) 반항하다 그림그리다(s): 을 위해 y 에 범위(10): 을 위해 x 에 범위(10): 인쇄하다 "%3d" % s.얻다(x, y), 인쇄하다 # 이제, 장식가들의 파이프라인을 구축하라. 랜덤_제곱 = 랜덤스퀘어(635) 임의_임의 = 캐시디코레이터(랜덤_제곱) max_max = 맥스디코레이터(임의_임의, 200) min_min = 민디코레이터(max_max, 100) 최종의 = VisibilityDecorator(min_min) 최종의.그림그리다()
참고:
Python 언어 기능인 Python Decorator와 Decorator Pattern(또는 위의 예와 같이 Python에서 이 디자인 패턴의 구현)을 혼동하지 마십시오.그것들은 다른 것이다.
Python Wiki 다음으로:
데코레이터 패턴은 디자인 패턴 북에 설명된 패턴이다.그것은 비슷한 인터페이스를 가진 장식용 물체 안에 물체의 행동을 감싸서 분명히 수정하는 방법이다.이것은 기능이나 클래스를 동적으로 수정하기 위한 언어 기능인 파이톤 데코레이터와 혼동해서는 안 된다.[7]
크리스털
추상적 계급 커피 추상적 반항하다 비용이 들다 추상적 반항하다 재료 종지부를 찍다 # 심플한 커피의 연장선상 계급 심플커피 < 커피 반항하다 비용이 들다 1.0 종지부를 찍다 반항하다 재료 "커피" 종지부를 찍다 종지부를 찍다 # 추상 장식가 계급 커피디코레이터 < 커피 보호의 게터 장식된_coffeecoffee : 커피 반항하다 초기화하다(@decorated_coffee) 종지부를 찍다 반항하다 비용이 들다 장식된_coffeecoffee.비용이 들다 종지부를 찍다 반항하다 재료 장식된_coffeecoffee.재료 종지부를 찍다 종지부를 찍다 계급 위드밀크 < 커피디코레이터 반항하다 비용이 들다 잘 하는 군요 + 0.5 종지부를 찍다 반항하다 재료 잘 하는 군요 + ", 우유" 종지부를 찍다 종지부를 찍다 계급 스프링클스 위드림 < 커피디코레이터 반항하다 비용이 들다 잘 하는 군요 + 0.2 종지부를 찍다 반항하다 재료 잘 하는 군요 + ", 스프링클스" 종지부를 찍다 종지부를 찍다 계급 프로그램 반항하다 인쇄하다(커피 : 커피) 놓다 "비용:#{커피.비용이 들다}; 재료:#{커피.재료}" 종지부를 찍다 반항하다 초기화하다 커피 = 심플커피.새로운 인쇄하다(커피) 커피 = 위드밀크.새로운(커피) 인쇄하다(커피) 커피 = 스프링클스 위드림.새로운(커피) 인쇄하다(커피) 종지부를 찍다 종지부를 찍다 프로그램.새로운
출력:
비용: 1.0; 재료: 커피 비용: 1.5; 재료: 커피, 우유 비용: 1.7; 재료: 커피, 우유, 스프링클
C#
네임스페이스 위키디자인패턴스; 공중의 접점 아이비케 { 끈을 매다 겟디테일즈(); 곱절로 하다 겟프라이스(); } 공중의 계급 알루미늄자전거 : 아이비케 { 공중의 곱절로 하다 겟프라이스() => 100.0; 공중의 끈을 매다 겟디테일즈() => "알루미늄 바이크"; } 공중의 계급 카본바이크 : 아이비케 { 공중의 곱절로 하다 겟프라이스() => 1000.0; 공중의 끈을 매다 겟디테일즈() => "탄소"; } 공중의 추상적 계급 바이크액세서리 : 아이비케 { 사유의 읽기 전용 아이비케 _자전거; 공중의 바이크액세서리(아이비케 자전거를 타다) { _자전거 = 자전거를 타다; } 공중의 가상의 곱절로 하다 겟프라이스() => _자전거.겟프라이스(); 공중의 가상의 끈을 매다 겟디테일즈() => _자전거.겟디테일즈(); } 공중의 계급 SecurityPackage : 바이크액세서리 { 공중의 SecurityPackage(아이비케 자전거를 타다):밑의(자전거를 타다) { } 공중의 무효로 하다 끈을 매다 겟디테일즈() => 밑의.겟디테일즈() + " + 보안 패키지"; 공중의 무효로 하다 곱절로 하다 겟프라이스() => 밑의.겟프라이스() + 1; } 공중의 계급 스포트패키지 : 바이크액세서리 { 공중의 스포트패키지(아이비케 자전거를 타다) : 밑의(자전거를 타다) { } 공중의 무효로 하다 끈을 매다 겟디테일즈() => 밑의.겟디테일즈() + " + Sport Package"; 공중의 무효로 하다 곱절로 하다 겟프라이스() => 밑의.겟프라이스() + 10; } 공중의 계급 바이크샵 { 공중의 정태의 공허하게 하다 UpgradeBike() { 시합을 하다 베이직바이크 = 새로운 알루미늄자전거(); 바이크액세서리 업그레이드된 = 새로운 스포트패키지(베이직바이크); 업그레이드된 = 새로운 SecurityPackage(업그레이드된); 콘솔.WriteLine($"Bike: '{upgrade.GetDetails()}' 비용: {업그레이드됨.GetPrice()}"); } }
출력:
자전거: '알루미늄 바이크 + 스포츠 패키지 + 보안 패키지' 비용: 111
참고 항목
참조
- ^ Gamma, Erich; et al. (1995). Design Patterns. Reading, MA: Addison-Wesley Publishing Co, Inc. pp. 175ff. ISBN 0-201-63361-2.
- ^ "How to Implement a Decorator Pattern". Archived from the original on 2015-07-07.
- ^ Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison Wesley. pp. 175ff. ISBN 0-201-63361-2.
{{cite book}}
: CS1 maint : 복수이름 : 작성자 목록(링크) - ^ "The Decorator design pattern - Problem, Solution, and Applicability". w3sDesign.com. Retrieved 2017-08-12.
- ^ Freeman, Eric; Freeman, Elisabeth; Sierra, Kathy; Bates, Bert (2004). Hendrickson, Mike; Loukides, Mike (eds.). Head First Design Patterns (paperback). Vol. 1. O'Reilly. pp. 243, 252, 258, 260. ISBN 978-0-596-00712-6. Retrieved 2012-07-02.
- ^ "The Decorator design pattern - Structure and Collaboration". w3sDesign.com. Retrieved 2017-08-12.
- ^ "DecoratorPattern - Python Wiki". wiki.python.org.
외부 링크
![]() | 위키북 컴퓨터 과학 디자인 패턴에는 다음과 같은 주제의 페이지가 있다.다양한 언어로 된 실내 장식기 구현 |