デザインパターン　Decoratorパターン

# Decoratorパターン
Decoratorパターンは、継承の代わりにコンポジションを使用するデザインパターン。

継承の代替手段として知られ、継承を利用するよりも柔軟に機能追加を行うことができる。**継承を避けたい場合に特に有用**。

継承がコンパイル時に機能を追加しているのに対して、Decoratorパターンはプログラムの実行時に機能を追加しているため、クラスの変更が最小限に抑えられ、柔軟性が向上する。

具体的には、オブジェクトをラップし、親クラスへの参照を保持したクラスを利用することで、ラップするごとに独自の機能を追加していくことができる。

ランタイム時に機能を追加することができ、これによって機能を拡張させることができる。

コードが複雑になるという欠点を持つ。

`java.io`パッケージの`InputStream`に関連するものや、UIフレームワークで利用されている。

## Decoratorパターンが利用できるシチュエーション
バーガーショップの注文システムを作成するとする。

バーガーは「ハンバーガー」「チーズバーガー」の２種類があり、その他オプションとして「ポテト」「サラダ」があるとして、オプションを追加したときの値段を求めるシステムとする。

## 必要な抽象クラス

場合によっては抽象クラスではなく、インターフェースを用いる場合もある。
![decorator.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1069520/ada331da-9026-f72a-8043-29c81970b2a1.png)

ここで重要なのは`ToppingsDecorator`は、`BurgerComponent`の機能を利用するために継承しているのではなく、同等に扱えるようにするために継承を行っているという点。

`ToppingsDecorator`と`BurgerComponent`には「**is - a**」ではなく「**has - a**」の関係がある。

```java:BurgerComponent.java
public abstract class BurgerComponent {
    // クライアントはcost()だけ知っていれば良い
    public abstract int cost();
}
```

```java:ToppingsDecorator.java
// Decoratorパターンでは、「同じ型として扱うための継承」を行う
// Decorator is Component. ではないが、Decorator has Component. の関係になっている
public abstract class ToppingsDecorator extends BurgerComponent {

    // Componentへの参照を保持する
    BurgerComponent burger;

    // Component を Decorator がラップする
    public ToppingsDecorator(BurgerComponent burger) {
        this.burger = burger;
    }

    public abstract int cost();
}
```
## 抽象クラスの継承
Componentを継承したクラス
```java:Hamburger.java
// ハンバーガーは Decorator ではなく、 Component
public class Hamburger extends BurgerComponent {

    int price;

    public Hamburger(){
        price = 120;
    }

    @Override
    public int cost() {
        return price;
    }
}
```

```java:CheeseBurger.java
// チーズバーガーも Decorator ではなく、 Component
public class CheeseBurger extends BurgerComponent {

    int price;

    public CheeseBurger() {
        price = 120;
    }

    @Override
    public int cost() {
        return price;
    }
}
```
Decoratorを継承したクラス
```java:Potato.java
// ポテトは Decorator
public class Potato extends ToppingsDecorator {

    int price;

    public Potato(BurgerComponent burger){
       // Component を Decorator でラップする
       super(burger);
       price = 50;
    }

    @Override
    public int cost() {
        // Decoratorが保持するComponentへの参照を利用して、機能を追加できる
        return burger.cost() + price;
    }
}
```

```java:Salad.java
// サラダも Decorator
public class Salad extends ToppingsDecorator {
   
    int price;

    public Salad(BurgerComponent burger) {
       // Component を Decorator でラップする
        super(burger);
        price = 70;
    }

    @Override
    public int cost() {
        // Decoratorが保持するComponentへの参照を利用して、機能を追加できる
        return burger.cost() + price;
    }
}
```

## Decoratorパターンの利用
クライアントは、`Component`が`cost()`を使えることだけを知っている。
```java:Main.java
public class Main {
    public static void main(String[] args) {
        // オプションをつけない注文
        BurgerComponent burger1 = new Hamburger();
        System.out.println("It's " + burger1.cost() + "yen");
        // >> It's 120yen

        // Component を Decorator でラップする
        BurgerComponent burger2 = new Salad(new Hamburger());
        System.out.println("It's " + burger2.cost() + "yen");
        // >> It's 190yen

        // 好きなだけラップできる
        BurgerComponent burger3 = new Potato(
                                    new Potato(
                                        new Salad(
                                            new Hamburger())));
        System.out.println("It's " + burger3.cost() + "yen");
        // >> It's 290yen
    }
}
```
## ポイント
+ Decoratorパターンでの機能の追加は、オブジェクトが保持している（**has a**）親クラスの処理の前後に、追加したい処理を加えることで行う。
+ Decoratorによるラップは、いくらでも（何層でも）行うことができる。
+ クライアントから見た時、Componentの実装を気にする必要がない（`cost()`というメソッドを持つことさえ知っていれば良い = <a href="https://qiita.com/AsahinaKei/items/1a2f48c13ae2caf37e91" target="_blank" rel="noopener noreferrer">透過的</a>
）。
+ Factoryパターンや、Builderパターンと併用されることが多い。
+ `Hamburger`や`CheeseBurger`などのクラス（Componentを継承したクラス）や、`Salad`や`Potato`などの小さなクラス（Decoratorを継承したクラス）が大量に作成される可能性があり、コードが複雑になることがある。

# 参考
・<a href="https://amzn.asia/d/8MCJXIB" target="_blank" rel="noopener noreferrer">Head Firstデザインパターン ―頭とからだで覚えるデザインパターンの基本</a>