객체에 새로운 책임을 동적으로 추가할 때 사용
1. 의도
•
GoF
◦
객체에 동적으로 새로운 책임을 추가 할 수 있게 합니다. 기능을 추가하려면, 서브클래스를 생성하는 것보다 융통성 있는 방법을 제공합니다.
•
Head First
◦
객체에 추가 요소를 동적으로 더 할 수 있습니다.
◦
데코레이터를 사용하면 서브클래스를 만들때보다 훨씬 유연하게 기능을 확장할 수 있습니다.
2. 활용성
•
동적으로 또한 투명하게, 다시 말해 다른 객체에 영향을 주지 않고 개개의 객체에 새로운 책임을 추가하기 위해 사용합니다.
•
제거될 수 있는 책임에 대해 사용합니다.
•
실제 상속으로 서브클래스를 계속 만드는 방법이 실질적이지 못할 때 사용합니다. 
◦
너무 많은 수의 독립된 확장이 가능할 때 모든 조합을 지원하기 위해 상속으로 해결하면 클래스 수가 폭발적으로 많아지게 됩니다.
◦
아니면 클래스 정의가 숨겨지든가, 그렇지 않더라도 서브클래싱을 할 수 없게 됩니다.
3. 구조
•
UML Class Diagram
4. 참여자
참여자  | 역할  | 예시  | 
Component  | 동적으로 추가할 서비스를 가질 가능성이 있는 객체들에 대한 인터페이스  | 자동차  | 
ConcreteComponent  | 추가적인 서비스가 실제로 정의되어야 할 필요가 있는 객체  | SM3  | 
Decorator  | Component 객체에 대한 참조자를 관리하면서 Component에 정의된 인터페이스를 만족하도록 인터페이스를 정의  | GPS 옵션, 시트 옵션  | 
ConcreteDecorator  | Component에 새롭게 추가될 서비스를 실제로 구현하는 클래스  | 현대 네비게이션, 가죽시트  | 
5. 협력 방법
•
Decorator는 자신의 Component 객체 쪽으로 요청을 전달합니다. 요청 전달 전 및 전달 후에 자신만의 추가 연산을 선택적으로 수행할 수 도 있습니다.
6. 결과
•
Pros
◦
단순한 상속보다 설계의 융통성을 더 많이 증대
▪
데코레이터 - 객체에 새로운 행동을 추가할 수 있는 가장 효과적인 방법
◦
클래스 계통의 상부측 클래스에 많은 기능이 누적되는 상황 회피 가능
▪
책임 추가 작업에서 필요한 비용만 그때 지불하는 방법을 제공
•
Cons
◦
데코레이터와 해당 그 데코레이터의 구성요소가 동일한 것은 아님
▪
데코레이터는 사용자에게 일관된 인터페이스를 제공하는 껍데기
▪
객체 식별자의 관점에서 구성요소와 이를 둘러싼 데코레이터 객체가 동일한 식별자를 가질 필요는 없음
◦
데코레이터를 사용함으로써 작은 규모의 객체들이 많이 생김
▪
클래스들이 어떻게 조합하여 새로운 모습과 기능을 만들어내는가에 따라서 새로운 객체가 계속 만들어짐
▪
객체들을 잘 이해하고 있다면 시스템 정의가 쉬우나, 그렇지 않으면 객체들을 모두 이해하고 수정하는 과정이 복잡함
7. 예시 코드
// Base Car class
class Car {
  public description: string;
  constructor() {
    this.description = "Basic car";
  }
  public cost(): number {
    return 10000;
  }
}
// Decorator class for GPS system
class GPSDecorator extends Car {
  private car: Car;
  constructor(car: Car) {
    super();
    this.car = car;
  }
  public get description(): string {
    return `${this.car.description}, GPS`;
  }
  public cost(): number {
    return this.car.cost() + 500;
  }
}
// Decorator class for leather seats
class LeatherSeatsDecorator extends Car {
  private car: Car;
  constructor(car: Car) {
    super();
    this.car = car;
  }
  public get description(): string {
    return `${this.car.description}, leather seats`;
  }
  public cost(): number {
    return this.car.cost() + 1000;
  }
}
// Client code
const basicCar = new Car();
console.log(basicCar.description, basicCar.cost()); // Basic car 10000
const carWithGPS = new GPSDecorator(basicCar);
console.log(carWithGPS.description, carWithGPS.cost()); // Basic car, GPS 10500
const carWithLeatherSeats = new LeatherSeatsDecorator(basicCar);
console.log(carWithLeatherSeats.description, carWithLeatherSeats.cost()); // Basic car, leather seats 11000
const carWithGPSAndLeatherSeats = new LeatherSeatsDecorator(new GPSDecorator(basicCar));
console.log(carWithGPSAndLeatherSeats.description, carWithGPSAndLeatherSeats.cost()); // Basic car, GPS, leather seats 11500
TypeScript
복사
