ちゃんなるぶろぐ

エンジニア5年生🧑‍💻 オライリーとにらめっこする毎日。

【5分でわかる☕️】TypeScriptでDesign Pattern〜Decorator Pattern〜

どうも、ちゃんなるです!

今回は、Decorator Patternを紹介します🖐️

概要

Decorator Patternは、既存のオブジェクトに新しい機能や振る舞いを追加する際に活用されるデザインパターンです。

このパターンを使用することで、オブジェクトの機能を拡張するために新たなサブクラスを作成する必要がなく、コードの複雑さを軽減できます。

今回示すプログラムの設計

今回のシナリオでは、カフェでコーヒーを注文するシステムを考えます。

コーヒーには様々な追加オプションがあります(ミルク、シロップ、ホイップクリームなど)。

Decorator Patternを使って、これらのオプションを簡単に追加・削除できるように設計しましょう。

サンプルコード

まず、飲み物を表す抽象クラスを定義し、getDescription()とcost()という2つの抽象メソッドを持たせます。

abstract class Beverage {
    abstract getDescription(): string;
    abstract cost(): number;
}

飲み物を拡張してコーヒーを用意します。

class Coffee extends Beverage {
    getDescription(): string {
        return "コーヒー";
    }

    cost(): number {
        return 200;
    }
}

飲み物を拡張してデコレーション材料を用意します。デコレーションする飲み物をコンストラクタで受け取ります。

abstract class CondimentDecorator extends Beverage {
    protected beverage: Beverage;

    constructor(beverage: Beverage) {
        super();
        this.beverage = beverage;
    }
}

デコレーションの材料たちです。

class Milk extends CondimentDecorator {
    getDescription(): string {
        return this.beverage.getDescription() + "、ミルク";
    }

    cost(): number {
        return this.beverage.cost() + 50;
    }
}

class Syrup extends CondimentDecorator {
    getDescription(): string {
        return this.beverage.getDescription() + "、シロップ";
    }

    cost(): number {
        return this.beverage.cost() + 30;
    }
}

class WhippedCream extends CondimentDecorator {
    getDescription(): string {
        return this.beverage.getDescription() + "、ホイップクリーム";
    }

    cost(): number {
        return this.beverage.cost() + 60;
    }
}

では、実際に注文してみましょう!

const coffee = new Coffee();
const coffeeWithMilk = new Milk(coffee);
const coffeeWithMilkAndSyrup = new Syrup(coffeeWithMilk);
console.log(coffeeWithMilkAndSyrup.getDescription()); // "コーヒー、ミルク、シロップ"
console.log(coffeeWithMilkAndSyrup.cost()); // 280

クラス図

サンプルコードのクラス図:Mermaid Live Editorで作成

Decorator Patternの使い道

機能の追加や削除が予測される場合や、オブジェクトに動的に機能を追加したい場合に適しています。

組み合わせられるデザインパターン

例えば、以下のデザインパターンと相性が良いです。

  • Factory Method Pattern: オブジェクトの生成をサブクラスに任せることで、インスタンス化の詳細を隠蔽し、柔軟なオブジェクト生成が可能になります。

chan-naru.hatenablog.com

  • Composite Pattern: 複数のオブジェクトをまとめて、一つのオブジェクトとして扱うことができます。これにより、単一のオブジェクトと複合オブジェクトを同一視できるため、コードの複雑さが軽減されます。また、新たなオブジェクトを追加する際にも、既存のコードを変更することなく簡単に組み込むことができます。

chan-naru.hatenablog.com

まとめ

Decorator Patternを使うと、オブジェクトに柔軟に機能を追加・削除でき、コードの複雑さを抑えることができます☕️👍

参考文献

www.oreilly.com

en.wikipedia.org