
타입스크립트로 작성된 데코레이터
데코레이터는 구조 패턴이며 새로운 행동들을 특수 래퍼 객체들 내에 넣어서 이러한 행동들을 객체들에 동적으로 추가할 수 있도록 합니다.
데코레이터를 사용하여 객체들을 제한 없이 래핑할 수 있습니다. 왜냐하면 대상 객체들과 데코레이터들은 같은 인터페이스를 따르기 때문입니다. 결과 객체는 모든 래퍼의 스태킹된 행동을 가질 것입니다.
복잡도:
인기도:
사용 예시들: 데코레이터는 타입스크립트 코드, 특히 스트림과 관련된 코드에서 꽤 표준적입니다.
식별: 데코레이터는 같은 클래스의 객체 또는 인터페이스를 현재 클래스로 수락하는 생성 메서드들 또는 생성자들로 인식할 수 있습니다.
개념적인 예시
이 예시는 데코레이터 패턴의 구조를 보여주고 다음 질문에 중점을 둡니다:
- 패턴은 어떤 클래스들로 구성되어 있나요?
- 이 클래스들은 어떤 역할을 하나요?
- 패턴의 요소들은 어떻게 서로 연관되어 있나요?
index.ts: 개념적인 예시
/**
* The base Component interface defines operations that can be altered by
* decorators.
*/
interface Component {
operation(): string;
}
/**
* Concrete Components provide default implementations of the operations. There
* might be several variations of these classes.
*/
class ConcreteComponent implements Component {
public operation(): string {
return 'ConcreteComponent';
}
}
/**
* The base Decorator class follows the same interface as the other components.
* The primary purpose of this class is to define the wrapping interface for all
* concrete decorators. The default implementation of the wrapping code might
* include a field for storing a wrapped component and the means to initialize
* it.
*/
class Decorator implements Component {
protected component: Component;
constructor(component: Component) {
this.component = component;
}
/**
* The Decorator delegates all work to the wrapped component.
*/
public operation(): string {
return this.component.operation();
}
}
/**
* Concrete Decorators call the wrapped object and alter its result in some way.
*/
class ConcreteDecoratorA extends Decorator {
/**
* Decorators may call parent implementation of the operation, instead of
* calling the wrapped object directly. This approach simplifies extension
* of decorator classes.
*/
public operation(): string {
return `ConcreteDecoratorA(${super.operation()})`;
}
}
/**
* Decorators can execute their behavior either before or after the call to a
* wrapped object.
*/
class ConcreteDecoratorB extends Decorator {
public operation(): string {
return `ConcreteDecoratorB(${super.operation()})`;
}
}
/**
* The client code works with all objects using the Component interface. This
* way it can stay independent of the concrete classes of components it works
* with.
*/
function clientCode(component: Component) {
// ...
console.log(`RESULT: ${component.operation()}`);
// ...
}
/**
* This way the client code can support both simple components...
*/
const simple = new ConcreteComponent();
console.log('Client: I\'ve got a simple component:');
clientCode(simple);
console.log('');
/**
* ...as well as decorated ones.
*
* Note how decorators can wrap not only simple components but the other
* decorators as well.
*/
const decorator1 = new ConcreteDecoratorA(simple);
const decorator2 = new ConcreteDecoratorB(decorator1);
console.log('Client: Now I\'ve got a decorated component:');
clientCode(decorator2);
Output.txt: 실행 결과
Client: I've got a simple component:
RESULT: ConcreteComponent
Client: Now I've got a decorated component:
RESULT: ConcreteDecoratorB(ConcreteDecoratorA(ConcreteComponent))