Autumn SALE
Decorator

Decorator を TypeScript で

Decorator 構造に関するパターンのひとつで オブジェクトをと呼ばれる特別なラッパー・オブジェクト内に配置することにより 新しい振る舞いを動的に追加できます

対象のオブジェクトとデコレーターは同じインターフェースに従うため デコレーターを使うと オブジェクトを何重にも包み込むことができます その結果として生成されるオブジェクトは 全部のラッパーの振る舞いを集積した振る舞いをします

複雑度

人気度

使用例 Decorator は TypeScript コードではかなり標準的で 特にストリームに関連するコードではよく使われます

見つけ方 Decorator は そのクラスと同じクラスまたはインターフェースのオブジェクトをパラメーターとして取る生成メソッドかコンストラクターの存在により識別できます

概念的な例

この例は Decorator デザインパターンの構造を説明するためのものです 以下の質問に答えることを目的としています

  • どういうクラスからできているか
  • それぞれのクラスの役割は
  • パターンの要素同士はどう関係しているのか

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))

他言語での Decorator

Decorator を C# で Decorator を C++ で Decorator を Go で Decorator を Java で Decorator を PHP で Decorator を Python で Decorator を Ruby で Decorator を Rust で Decorator を Swift で