Skip to content

デコレーターパターン

公開日:November 17, 2024更新日:November 28, 2024
TypeScriptDesign pattern📄

デコレーターパターン

デコレーターパターン(Decorator Pattern) は、既存のオブジェクトに対して動的に新しい機能を追加するためのデザインパターンです。このパターンは、オブジェクトをラップすることによって、新しい機能を柔軟に追加したり、既存のクラスの挙動を変更したりすることを可能にします。

デコレーターパターンは、継承の代替として使用され、特に複数の異なる機能を組み合わせて動的にオブジェクトに付加したい場合に有効です。TypeScriptでは、デコレーター構文を使用してこのパターンを実装できます。

TypeScriptでのデコレーターパターンの実装

TypeScriptには、クラス、メソッド、プロパティなどに対してデコレーターを適用できる機能があります。以下に、クラスに対して新しい機能を追加するデコレーターパターンの例を示します。

コーヒーに追加トッピングを行うデコレーターパターンの例

typescript
// コーヒーインターフェース
interface Coffee {
  cost(): number;
  description(): string;
}

// シンプルなコーヒーの実装
class SimpleCoffee implements Coffee {
  cost(): number {
    return 5;
  }

  description(): string {
    return 'Simple Coffee';
  }
}

// 抽象デコレータークラス
class CoffeeDecorator implements Coffee {
  protected decoratedCoffee: Coffee;

  constructor(coffee: Coffee) {
    this.decoratedCoffee = coffee;
  }

  cost(): number {
    return this.decoratedCoffee.cost();
  }

  description(): string {
    return this.decoratedCoffee.description();
  }
}

// ミルクデコレーター
class MilkDecorator extends CoffeeDecorator {
  cost(): number {
    return super.cost() + 2;
  }

  description(): string {
    return super.description() + ', Milk';
  }
}

// シナモンデコレーター
class CinnamonDecorator extends CoffeeDecorator {
  cost(): number {
    return super.cost() + 1.5;
  }

  description(): string {
    return super.description() + ', Cinnamon';
  }
}

// 実際の使用例
let myCoffee: Coffee = new SimpleCoffee();
console.log(`${myCoffee.description()} costs $${myCoffee.cost()}`); // Simple Coffee costs $5

myCoffee = new MilkDecorator(myCoffee);
console.log(`${myCoffee.description()} costs $${myCoffee.cost()}`); // Simple Coffee, Milk costs $7

myCoffee = new CinnamonDecorator(myCoffee);
console.log(`${myCoffee.description()} costs $${myCoffee.cost()}`); // Simple Coffee, Milk, Cinnamon costs $8.5

解説

  1. Coffeeインターフェース

    • Coffeeインターフェースは、すべてのコーヒーが実装すべきcostdescriptionメソッドを定義しています。
  2. SimpleCoffeeクラス

    • SimpleCoffeeクラスは、基本的なコーヒーのコストと説明を提供します。このクラスは最もシンプルな形でのコーヒーを表します。
  3. CoffeeDecoratorクラス(抽象デコレーター)

    • CoffeeDecoratorは、デコレーターパターンの基盤となるクラスです。このクラスはCoffeeインターフェースを実装しており、既存のCoffeeオブジェクトをラップして動作を拡張します。
  4. 具体的なデコレータークラス(MilkDecoratorとCinnamonDecorator)

    • MilkDecoratorCinnamonDecoratorは、CoffeeDecoratorを継承し、それぞれミルクやシナモンを追加する役割を持っています。costメソッドで追加のコストを計算し、descriptionメソッドで説明を更新します。
  5. 実際の使用例

    • 最初にシンプルなコーヒーを作成し、次にそれにミルクやシナモンを追加していきます。各デコレーターを追加するごとに、コーヒーのコストと説明が更新されます。

利点

  • 柔軟性の向上: 継承を使わずに既存のオブジェクトに新しい機能を追加できるため、コードの柔軟性が向上します。
  • オープン/クローズド原則に準拠: クラスの変更をせずに機能を拡張できるため、オープン/クローズド原則(拡張にはオープンだが、修正にはクローズド)を遵守できます。

使用例

  • UIコンポーネントの装飾: ボタンにアイコンやラベルを動的に追加する場合など、UIコンポーネントのカスタマイズに使われます。
  • データストリームの処理: JavaScriptやTypeScriptにおけるデータストリームの処理で、各ステップに機能を追加するために使用できます(例: ロギング、暗号化、圧縮など)。

まとめ

デコレーターパターンは、既存のオブジェクトに対して動的に機能を追加する柔軟な方法を提供します。TypeScriptのクラスとインターフェースを使ってこのパターンを実装することで、コードの再利用性と柔軟性を高めることが可能です。

このパターンを理解し、適切に利用することで、特に動的に機能を追加したり、複数の機能を組み合わせる必要がある場面で強力なツールとなります。