24 Aug 2019

디자인 패턴 09 - 장식자 (Decorator)

장식자(Decorator) 패턴은 객체에 동적으로 새로운 기능이나 책임을 추가할 수 있게 해주는 패턴이다. 상속을 통해 서브클래스를 추가하여 기능을 추가하는 것보다 융통성이 있다.

보통 어느 특정 클래스에 기능 추가가 필요할 때 일반적인 방법은 상속을 이용하는 것이다. 즉, 기능을 추가할 타겟 클래스를 상속받아 새로운 서브 클래스를 만들어 기능을 추가하는 방법이 있지만 별로 유용하지는 않다. 기능을 추가하는 방법이 정적이기 때문에, 사용자 입장에서는 추가 기능을 부여하는 것을 동적으로 제어할 수 없다.

장식자 패턴은 추가 기능을 구현하는 장식자(Decorator)가 타겟 객체를 감싸는 형식이다. 장식자는 자신이 둘러싼 요소인 타겟 객체의 연산을 자신도 동일하게 정의한다. 따라서 장식자의 존재는 사용자에게 감춰질 수 있으며, 장식자는 자신이 둘러싼 타겟 객체로 전달되는 요청을 중간에 가로채어 대신 전달한다.

00.png

중간에 요청을 가로채므로, 이 전달과정의 앞뒤로 기능을 추가할 수 있으며 인터페이스는 동일하므로 장식자의 중첩도 가능해진다. 따라서 기능 추가하는 것을 무한정으로 할 수 있다.

장식자와 타겟 객체의 연산이 동일하다는 것은 동적으로 투명하게 (사용자는 모르게) 기능을 타겟 객체에 부여할 수 있다는 것이다. 또한 타겟 객체의 입장에서는 장식자의 존재를 모른다. 장식자는 타겟 객체에 대해 투명하다.

01.png

장식자는 위와 같이 똑같은 연산을 정의하기 위해 타겟 클래스의 부모 인터페이스를 상속하며, 타겟 클래스의 객체를 필드로서 참조한다. 그리고 타겟 객체에 대한 요청을 중간에 가로채어 전달한다. 요청 전달 전후로 장식자는 자신만의 추가 기능을 선택적으로 수행한다.

기능 추가시 서브 클래스를 따로 정의하는 상속을 하는 것에 비해 장식자 패턴을 사용함으로써 얻는 이익은 설계의 융통성을 증대시킬 수 있다는 것이다. 이 패턴은 기존 객체에 새로운 행동을 추가할 수 있는 가장 효과적인 방법으로, 런타임에 타겟 객체에 장식자를 연결하거나 분리함으로써 사용자로 하여금 기능 추가/삭제를 동적으로 제어할 수 있게 해준다. 또한 여러 장식자들을 조합하여 복합적인 기능을 부여할 수도 있다. 만약 상속을 통해 기능 추가를 하려고 했다면 각 기능마다 서브 클래스를 정의해야하고, 이는 클래스의 수를 증가시킨다.

타겟 클래스와 장식자의 공통 부모인 Component 인터페이스는 불필요하게 무거우면 안된다. 이 말은 Component는 무언가를 저장하는 필드를 가지지 말라는 의미이다. 만약 Component에 필드가 정의되어 있다면, 장식자는 불필요하게 무거워질 뿐만 아니라, 자신의 고유 책임과는 별 상관없는 필드들을 쓸데없이 가지게 될 수도 있다.

적응자(Adapter) 패턴의 객체 구성 방식이 장식자 패턴과 유사하나 Adapter는 사용할 인터페이스를 맞추기 위한 목적으로 사용하는 반면, 장식자는 타겟 객체에 기능을 추가함으로써 원래의 행동을 변화시킨다.

Decorator Example


Tags:
Stats:
0 comments