본문 바로가기
SW

GoF의 디자인 패턴(Design Patterns: Elements of Reusable Object-Oriented Software) - 4장 구조 패턴 :: 장식자(Decorator)

by 라꾸스떼(YR) 2020. 4. 28.
반응형

[장식자(Decorator) - 객체 구조]

<의도>

객체에 동적으로 새로운 책임을 추가할 수 있게 한다.

 

<다른 이름>

랩퍼(Wrapper)

 

<동기>

새로운 서비스의 추가가 필요할 때 이를 해결하는 일반적인 방법은 상속을 이용하는 것이다. 즉, 이미 존재하는 클래스를 상속받고, 또 다른 클래스에서 테두리 속성을 상속받아 이 서브클래스의 인스턴스에 테두리가 있도록 하는 방법이다. 더 나은 방법으로 지금 필요한 테두리를 추가하는 다른 객체에다가 해당 구성요소를 둘러싸는 것이다. 이렇게 무엇인가를 감싸는 객체를 장식자(decorator)라고 한다. 장식자는 자신이 둘러싼 요소, 구성요소가 갖는 인터페이스를 자신도 동일하게 제공하므로, 장식자의 존재는 이를 사용하는 사용자에게 감춰진다. 즉, 장식자는 자신이 둘러싼 구성요소로 전달되는 요청을 중간에 가로채서 해당 구성요소에 전달해 준다.

Decorator 클래스의 서브클래스는 필요한 서비스를 구현하기 위해서 특정 기능을 수행하는 메서드를 추가로 구현할 수 있다. 장식자 패턴의 중요한 특성은 장식자는 어떤 형태의 Visual-Component에 모두 적용할 수 있다.

 

<활용성>

-동적으로 또한 투명하게(transparent), 다시 말해 다른 객체에 영향을 주지 않고 개개의 객체에 새로운 책임을 추가하기 위해 사용한다.

-제거될 수 있는 책임에 대해 사용한다.

-실제 상속으로 서브클래스를 계속 만드는 방법이 실질적이지 못할 때 사용한다.

 

<구조>

-

 

<참여자>

-Component : 동적으로 추가할 서비스를 가질 가능성이 있는 객체들에 대한 인터페이스

-ConcreteComponent : 추가적인 서비스가 실제로 정의되어야 할 필요가 있는 객체

-Decorator : Component 객체에 대한 참조자를 관리하면서 Component에 정의된 인터페이스를 만족하도록 인터페이스를 정의

-ConcreteDecorator : Component에 새롭게 추가할 서비스를 실제로 구현하는 클래스

 

<협력 방법>

Decorator는 자신의 Component 객체 쪽으로 요청을 전달한다. 요청 전달 전 및 전달 후에 자신만의 추가 연산을 선택적으로 수행할 수도 있다.

 

<결과>

1.단순한 상속보다 설계의 융통성을 더 많이 증대시킬 수 있다. 장식자를 사용하면 장식자를 객체와 연결하거나 분리하는 작업을 통해 새로운 책임을 추가하거나 삭제하는 일이 런타임에 가능해진다. 그러나 상속은 코드에서, 즉 정적으로 새로운 클래스를 추가해야만 추가적인 행동을 정의할 수 있는 방법이다.

2.클래스 계통의 상부측 클래스에 많은 기능이 누적되는 상황을 피할 수 있다. 장식자 패턴은 책임 추가 작업에서 “필요한 비용만 그때 지불하는” 방법을 제공한다.

3.장식자와 해당 그 장식자의 구성요소가 동일한 것은 아니다. 장식자는 사용자에게 일관된 인터페이스를 제공하는 껍데기이다.

4.장식자를 사용함으로써 작은 규모의 객체들이 많이 생긴다. 클래스들이 어떻게 조합하여 새로운 모습과 기능을 만들어내는가에 따라서 새로운 객체가 계속 만들어지기 때문이다.

 

<구현>

고려할 사항들

1.인터페이스 일치시키기. Decorator 객체의 인터페이스는 반드시 자신을 둘러싼 구성요소의 인터페이스를 만족해야 한다.

2.추상 클래스로 정의되는 Decorator 클래스 생략하기. 간혹 추상 클래스인 Decorator 클래스를 정의할 필요가 없을 때도 있다. 이때 구성요소에게 요청을 전달하는 Decorator 클래스의 책임을 ConcreteDecorator 클래스와 합칠 수 있다.

3.Component 클래스는 가벼운 무게를 유지하기. 인터페이스를 만족하는 확인하려면 구성요소와 Decorator 모두 동일한 부모 클래스인 Component 클래스를 상속받아야 한다. 이럴 때 Component 클래스를 가볍게 정의하는 것은 중요한 일이다. 가볍게 정의한다는 의미는 연산에 해당하는 인터페이스만을 정의하고 무언가 저장할 수 있는 변수는 정의하지 말라는 의미이다. 데이터 저장소를 정의하는 것은 서브클래스에서 할 일이다.

4.객체의 겉포장을 변경할 것인가, 속을 변경할 것인가. 전략 패턴에서 구성요소는 자신이 받은 처리 요청을 분리된 Strategy 클래스에 전달한다. 전략 패턴에서는 Strategy 객체의 대체를 통해서 구성요소의 기능성을 변경하거나 확장하는 방법을 제공한다. 장식자 패턴은 객체의 외관을 변경하는 것이므로, 구성요소는 자신을 둘러싼 장식자에 대해서는 전혀 알 필요가 없다. 즉, 장식자는 구성요소에 대해 투명한다. 전략을 사용한다면, 구성요소는 자신이 사용할 전략에 대한 참조자가 있고, 이것을 유지해야만 다양한 확장 기능을 얻을 수 있다.

 

<예제 코드>

Decorator의 서브클래스는 새로운 기능에 대한 구현 방법을 정의한다. 그리고 Decorator에 정의된 모든 구현을 상속받는다.

 

<잘 알려진 사용예>

많은 객체지향 사용자 인터페이스 툴킷에서 위젯의 기능을 추가하고자 할 때 장식자 패턴을 많이 사용한다.

 

<관련 패턴>

적응자 패턴 : 원래의 적응자는 인터페이스를 변경시켜주는 것이었지만, 장식자는 객체의 책임, 행동을 변화시킨다.

복합체 패턴 : 목적은 객체의 합성이 아니라 객체에 새로운 행동을 추가하기 위한 것이다.

전략 패턴 : 장식자는 객체의 겉모양을 변경하고, 전략은 객체의 내부를 변화시킨다.

반응형

댓글