디자인 패턴 - 03. 데코레이터 패턴

강준혁·2022년 9월 30일
0

디자인패턴

목록 보기
3/6

데코레이터 패턴

데코레이터 패턴은 객체의 결합 을 통해 기능을 동적으로 유연하게 확장 할 수 있게 해주는 패턴으로, 기본 기능에 추가할 수 있는 기능의 종류가 많은 경우에 각 추가 기능을 Decorator 클래스로 정의 한 후 필요한 Decorator 객체를 조합함으로써 추가 기능의 조합을 설계 하는 방식이다.

데코레이터 패턴의 필요성

요리를 하는 Cook 인터페이스가 있다고 하자.

interface Cook {
  public void cooking();
}

고기 요리를 하는 클래스를 만든다.

class MeetCook implements Cook {
  public void cooking() {
    System.out.println("고기를 굽습니다.");
  }
}

소금을 뿌린 고기요리를 하는 클래스를 만들어야 하는경우,
기존 코드를 확장하기 위한 가장 쉬운 방법으로 상속을 활용한다.

class SaltedMeetCook extends MeetCook {
  public void cooking() {
    super.cooking();
    System.out.println("소금을 뿌립니다.");
  }
}

이와 같은 방법으로 확장을 할 경우 고객의 취향에 따라 소금을 두번, 세번, 그 이상 뿌려야 한다거나 후추를 뿌리거나 기름을 둘러야 하는 경우가 생긴다면
그 조합의 경우의 수만큼 클래스가 추가되어야 한다.

합성을 통한 구현

상속이 아닌 합성을 통하면 보다 유연한 설계가 가능하다.

class SaltDecorator implements Cook {
  private Cook cook;
  
  public SaltDecorator(Cook cook) { this.cook = cook }
  
  public void cooking() {
    cook.cooking();
    System.out.println("소금을 뿌립니다.");
  }
}
Cook cook = new SaltDecorator(new MeetCook());
cook.cooking(); // 고기를 굽습니다, 소금을 뿌립니다.

하지만 추가적인 데코레이터가 필요한 경우, 중복 코드가 발생한다.

class PepperDecorator implements Cook {
  private Cook cook; // 중복!
  
  public PepperDecorator(Cook cook) { this.cook = cook } // 중복!
  
  public void cooking() {
    cook.cooking();
    System.out.println("후추를 뿌립니다.");
  }
}

합성을 사용하여 설계를 유연하게 하고, 추가 기능을 구현하는 클래스들의 중복을 추상화하여 구현한 패턴이 데코레이터 패턴이다.

데코레이터 패턴의 적용

Cook 클래스를 장식할 데코레이터의 추상 클래스를 만든다.

abstract class CookDecorator implements Cook {
  private Cook cook;
  
  public CookDecorator(Cook cook) {
    this.cook = cook;
  }
  
  public void cooking() {
    cook.cooking();
  }
}

필요한 데코레이터의 클래스들을 만든다.

class SaltDecorator extends CookDecorator {
  public SaltDecorator(Cook cook) { super(cook); }
  
  @Override
  public void cooking() {
    super.cooking();
    System.out.println("소금을 뿌립니다.");
  }
}

class PepperDecorator extends CookDecorator {
  public PepperDecorator(Cook cook) { super(cook); }
  
  @Override
  public void cooking() {
    super.cooking();
    System.out.println("후추를 뿌립니다.");
  }
}

아래와 같이 추가적인 클래스 없이 필요에 따라 다양한 조합을 만들어낼 수 있다.


Cook saltedMeet = new SaltDecorator(new MeetCook());
saltedMeet.cooking(); // 고기를 굽습니다, 소금을 뿌립니다

Cook saltedAndPepperMeet = new SaltDecorator(new PepperDecorator(new MeetCook()));
// 고기를 굽습니다, 후추를 뿌립니다, 소금을 뿌립니다
profile
백엔드 개발자

0개의 댓글