Search
Duplicate
🎨

[디자인 패턴 - 구조 패턴] 데코레이터 패턴 (Decorator)

객체에 새로운 책임을 동적으로 추가할 때 사용

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
복사