본문 바로가기

Design Patterns

Decorator Pattern ③ 적용 및 정리

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.
일단은 데코레이터 패턴에 대한 정의는 이렇습니다.
테코레이터 패턴에서는 객체에 추가적인 요건을 동적으로 첨가한다. 데코레이터는 서브클래스를 만드는 것을 통해서 기능을 유연하게 확장할 수 있는 방법을 제공한다.

-_-; 당췌 뭐라고 하는건지 알수가 없네요.. 역시나 말로 하는것보다는 그림으로 보면서 이해하는편이 훨씬 빠를것 같다는 생각이 듭니다. 뭔가 정의 내리는 건 책에서도 처음부터 하고 있지 않는걸 보니 정의는 언제나 그럴싸 하기때문에 온갖 어려운 미사여구로 장식되어 있기 때문에 와닿지 않는 것 같네요. 그럼 멋진말 다 뒤집어 엎고 이해하기 위해서.. 다른방법으로 접근을 합시다!

인터넷을 통해서 아래와 같은 다이어그램을 구할 수 있었습니다.
사용자 삽입 이미지

이것이 데코레이터 패턴의 일종의 모형이라고 볼수가 있는데요. Component라는 인터페이스가 존재하고 이걸 구현하는 구상클래스로는 Decorator 클래스가 있고, ConcreteComponent 클래스가 있습니다. Decorator 클래스에는 Component 객체를 구성요소로 가지고 있다는 표시도 되어있습니다. Decorator의 구상클래스로 또 두개가 있는것을 볼 수가 있습니다.

추가적인 요건들을 동적으로 첨가한다는 의미는 역시나 Decorator 클래스에 Component의 객체가 구성 요소로 있기 때문인것 같고, 기능을 유연하게 확장한다는 의미는 데코레이터의 구상 클래스를 추가 시켜주는 것 만으로 상위 클래스나 다른 클래스의 변경이 없기 때문이라고 볼 수 있겠군요. OCP에 준거하고 있습니다 ^^


이전에 만들었던 영화 티켓 소스코드를 수정함으로서 데코레이터 패턴을 좀 더 배워보도록 하겠습니다. 먼저 위와 같은 모습의 다이어그램으로 만들어 보도록 하겠습니다 ^^;

사용자 삽입 이미지

요러한 형태의 다이어그램이 나옵니다. 예쁘지요 +_+ 일단 인터페이스가 되는 컴포넌트 인터페이스는 추상클래스인 MovieTicket 클래스가 되겠습니다. 요걸 상속 받는 4가지 연령별 유형의 티켓이 존재하고, 이 티켓을 할인해주는 TicketDecorator라는 추상클래스가 또 있습니다. 그리고 TicketDecorator의 구상 클래스로 멤버쉽카드 할인해주는 클래스, 영화의날에 할인해주는 클래스, VIP카드 할인해주는 클래스가 있습니다!!

음.. 위에 있는 다이어그램과 다른점이라고 한다면, 처음에 컴포넌트 인터페이스를 구현하는 구조가 아니라, 상속을 사용하는 구조라는점에서 의문점을 가질 수 있겠는데요. 여기서는 상속을 이용해서 MovieTicket 클래스의 행동을 물려 받는게 목적이 아니라 ^^; 상속을 사용해서 pay() 메소드를 정의하게끔 하는데 의의가 있으니 이해해주시길 바랍니다!!


주목 해야하는 부분은 저 할인 클래스(데코레이터 구상 클래스)들의 멤버변수로 MovieTicket의 객체를 가지고 있다는점이죠 +_+ 왜냐구요??? 저 부분에서 할인이 되거든요 +_+ 어떻게 할인이 되는지 한번 살펴 봅시다!!

VipCard 클래스의 소스코드 입니다.

public class VipCard extends TicketDecorator {

      MovieTicket movieTicket;


      public VipCard(MovieTicket movieTicket) {

            this.movieTicket = movieTicket;

      }


      public String getType() {

            return movieTicket.getType() + " + VIP 카드 할인";

      }


      public int pay() {

            return movieTicket.pay() - 1500;

      }

}

먼저 생성자를 살펴보면 인수로 MovieTicket의 객체를 받구요, 요기서 가격정보와 Type정보를 가져 오겠지요.. ^^ movieTicket.pay() 메소드를 호출해서 유도리 있는 가격 정보를 불러온 후에.. 1500원을 할인 해주는 군요.. +_+ movieTicket이라는 객체명으로 이를 구현,상속하는 어느 구체화된 클래스가 오던간에 유동적으로 커버를 해주게 되는 겁니다 ^^ 멋지네요..

그럼 테스트코드를 사용해서 테스트를 한번 해보도록 하죠 +_+

public class TicketMaker {

      public static void main(String[] args) {

            MovieTicket ticket = new AdultTicket();

            ticket = new MembershipCard(ticket);

            ticket = new MovieDayEvent(ticket);

            MovieTicket ticket1 = new JuniorTicket();

            ticket1 = new VipCard(ticket1);

            System.out.println("<<<< " + ticket.getType() + " >>>>");

            System.out.println("가격 : " + ticket.pay());

            System.out.println("<<<< " + ticket1.getType() + " >>>>");

            System.out.println("가격 : " + ticket1.pay());

      }

}


사용자 삽입 이미지

할인이 잘 되네요 ^^ 일단 구조를 잘 살펴보면 이렇습니다 먼저 AdultTicket 객체를 생성한후에 MembershipCard로 데코레이트 해준후에 다시 MovieDayEvent로 데코레이트를 해줍니다 +_+ 다음으로는 JuniorTicket을 생성한후에 VIP 카드 할인을 데코레이트 합니다. 다른 할인 정책이나, 할인율이 바뀌어도 전체적인 코드의 변화는 전혀 없겠지요 +_+


자바 API에서 데코레이터 패턴을 사용한 경우가 java.io 패키지라고 하네요 ^^ 입출력에 대해서 많이 공부한 경험이 있는데 이게 데코레이터 패턴을 사용했다고 하니 괜시리 반갑습니다.

여기서 데코레이터 패턴의 단점을 발견할 수 있다고 하네요. 데코레이터 패턴을 이용해서 디자인을 하다 보면 잡다한 클래스들이 너무 많아진다고 합니다. 따라서 데코레이터 패턴을 사용해서 디자인 하기 경우에 본인 이외에 다른사람이 이해하기 힘든 디자인이 되고는 한다고 하네요. 그래보이기는 합니다만 -_-;; 여기서는 잘 모르겠네요.

확실히 입출력 부분을 공부하면서 너무 많이 Wrapping하는 것을 보면서 복잡하다고 여겼었는데, 그런 가독성의 문제가 있는듯 합니다.