본문 바로가기

Design Patterns/내 생각

Decorator 패턴에 대한 생각 정리

안녕하세요.

오늘은 Decorator 패턴에 대해 생각이 정리된 부분을 이야기 해볼까 합니다.


Decorator 패턴에 대한 설명은 위의 링크를 따라 들어가서 보시면 될 것 같구요.


Decorator패턴은 굉장히 간단하고 멋져보이는 패턴입니다.

저도 처음 봤을 때 "우와~ 이런방법이 있구나~" 하면서 놀랐죠.


하지만 막상 실전에 어떻게 활용해야할 지 막막하더군요...

그래서 내린 결론은 

디자인 패턴을 이해한다는 것은 단순히 클래스 관계를 이해하는 것뿐만 아니라, 언제 어떤 의도로 이 패턴이 사용될 수 있는지를 이해하는게 더 중요하다.

라는 것 입니다.


많은 책에서 Decorator패턴을 설명할 때에 커피의 가격 계산에 대한 예를 사용하거나, 윈도우에 스크롤뷰와 프레임을 붙이는 등의 상황을 예로 듭니다. 


그런데 아무리 생각해봐도 이러한 상황에 Decorator패턴을 쓰는게 가능한지 잘 모르겠더군요.




먼저, 커피의 경우에는 Decorator패턴이 정말이지 가격 계산에만 쓰일 수 있는 것 같습니다. 즉, 커피 자체에 대해 Decorator패턴을 적용할 수 있는게 아니라, 커피의 가격에 대해서만 적용이 가능하다는 것입니다. (물론, 커피의 가격만 계산하는 프로그램이라면 전혀 문제될 것이 없지만, 커피의 향이나 색 등을 표현하기에는 Decorator 패턴만으로는 부족하다는 것입니다.)


윈도우 예의 경우에는 윈도우에 스크롤을 입힌다는데, 스크롤 뷰라는게 단순히 뷰만 있는게 아니고 윈도우 내의 컨텐츠 움직임에 따라 스크롤의 길이와 위치가 변화하게 되는데 이런 부분까지 다 표현하는게 가능할까...라는 점입니다.

(이를 Decorator패턴으로 설계 가능하다고 생각하시는 분은 저에게 가르침을 주세요~^^)




이렇게 기존의 예에 대한 이해부족으로 실제로 적용 가능한 상황이 어떤게 있을까.. 하고 생각을 해보게 되었습니다.


터치 효과 Touch Effect

제가 생각한 예는 화면을 터치했을 때 특수한 효과가 나는 예입니다. 

화면을 터치하면 진동이 나올 수도 있고, 터치한 주위로 꽃들이 터질 수도 있고, 화면이 깨지는 효과가 나올 수도 있죠.

또 이들 효과가 2개 이상 동시에 발동될 수도 있습니다.


이러한 효과가 한번에 하나만 가능하다면 Strategy 패턴같은 방법으로 구현이 가능하겠죠. 

하지만 동시에 여러가지 효과가 발동되어야 한다면 Strategy패턴으로 구현하기보다는 Decorator패턴을 이용하는게 좋을 것 같습니다. 


먼저 클래스 다이어그램부터 보시죠.




클래스 구조는 전형적인 Decorator패턴의 모습입니다.

이렇게 Decorator패턴을 이용해서 설계를 하면 생길 수 있는 장점에 대해 이야기를 해보죠.


1. 상태 변수를 이용해 프로그래밍하는 것보다 훨씬 코드가 간결해진다.

첫 번째 장점은 상태 변수를 이용해 프로그래밍하는 것보다 코드가 간결해진다는 점입니다.

즉, 터치 효과를 저장하는 int형의 멤버 변수를 만들고 이 멤버 변수에 어떤 효과들이 설정되어있는지 설정값을 담아둘 수 있습니다. 


public static final int TOUCH_EFFECT_FLOWER = 1 << 0;
public static final int TOUCH_EFFECT_CRACK = 1 << 1;
public static final int TOUCH_EFFECT_VIBRATION = 1 << 2;

private int _touchEffects = TOUCH_EFFECT_FLOWER | TOUCH_EFFECT_CRACK;


이렇게 _touchEffects 변수에 터치 효과들을 담아두고 있다가, 사용하는 곳에서 변수를 체크해서 적절한 효과를 발동시키는 겁니다. 

 

public void onTouch(float x, float y) {
    if(_touchEffects & TOUCH_EFFECT_FLOWER == TOUCH_EFFECT_FLOWER) {
        //꽃 효과를 발동한다.
    }

    if(_touchEffects & TOUCH_EFFECT_CRACK == TOUCH_EFFECT_CRACK) {
        //액정이 깨진 효과를 발동한다.
    }

    if(_touchEffects & TOUCH_EFFECT_VIBRATION == TOUCH_EFFECT_VIBRATION) {
        //진동 효과를 발동한다. 
    }
}


이렇게 사용하는 터치 효과를 발동해야 하는 곳에서 _touchEffects 변수를 체크해서 사용해야 합니다.

이렇게 사용하는 것의 단점이 뭘까요?

솔직히 복잡하게 설계를 하는 것보다 이렇게 쓰는게 훨씬 빨리 코딩할 수 있는 방법아닐까요?


지금 보여진 코드만 보면 그렇습니다.

하지만,, _touchEffects라는 변수는 여기에서만 사용되지 않을 수도 있습니다.

다른 메서드에서도 저런 분기문을 똑같이 사용할 수 있습니다.

또 효과가 하나씩 늘어날 때마다 _touchEffects 변수를 사용하는 곳의 코드를 또 추가적으로 작성해야 하구요.

그렇게 _touchEffects를 사용하는 메서드가 늘어날수록 코드는 더욱더 복잡해지고, 수정을 위해 많은 시간과 노력을 요할 수 있습니다.


2. Strategy 패턴을 이용하는 설계보다 클래스 수를 훨씬 줄일 수 있다.

만약 Decorator패턴을 사용하지 않고, Strategy패턴을 이용해 설계를 하면 이 경우에는 훨씬 많은 수의 클래스가 필요할 수 있습니다.

혹시 오해하실까봐 말씀드리는데 Strategy패턴이 Decorator패턴보다 좋지 않다는게 아니라, 지금 제가 말씀드리고 있는 이 상황에서 그렇다는 겁니다.  



먼저 이 상황을 다시 한번 설명 드리자면, 동시에 여러개의 효과가 발동될 수 있습니다.


즉, 꽃 효과와 진동효과가 동시에 발동되거나 진동효과와 액정 깨짐 효과가 동시에 발동될 수도 있습니다.

이를 Strategy패턴으로 구현하려면 TouchEffect인터페이스를 상속받는 FlowerTouchEffect, VibrationTouchEffect, CrackTouchEffect뿐만 아니라 이들을 조합한 FlowerVibrationTouchEffect, FlowerCrackTouchEffect ..등등 많은 수의 서브 클래스가 필요하게 됩니다.


정리

이렇게 수평적인 관계의 여러 기능을 동적으로 결합해야하는 경우에 Decorator패턴이 잘 사용될 수 있을 것 같습니다. 


또 다르게 사용될 수 있는 방법이 생각난다면 다음 번에 포스팅하기로 하죠~^^

'Design Patterns > 내 생각' 카테고리의 다른 글

싱글톤과 상태 값  (0) 2012.08.01