Swiftでデザインパターン【Decorator】

元ネタ → [ochococo/Design-Patterns-In-Swift](https://github.com/ochococo/Design-Patterns-In-Swift#-decorator)

# クラス図
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37598/10809746-bdbf-4d0f-33e4-40f1d7e31718.png)



図の引用元：[Wikipedia: Decorator パターン](https://ja.wikipedia.org/wiki/Decorator_%E3%83%91%E3%82%BF%E3%83%BC%E3%83%B3)

# 概要
The decorator pattern is used to extend or alter the functionality of objects at run- time by wrapping them in an object of a decorator class. This provides a flexible alternative to using inheritance to modify behavior.
Decoratorパターンは、Decoratorクラスのオブジェクトでオブジェクトをラップすることにより、実行時にオブジェクトの機能を拡張または変更するために使用する。継承を使用して動作を変更する代わりに柔軟な方法を提供する。

# サンプルコード
```swift
// Component
protocol CostHaving {
    // operation
    var cost: Double { get }
}

// Component
protocol IngredientsHaving {
    // operation
    var ingredients: [String] { get }
}

// Component
typealias BeverageDataHaving = CostHaving & IngredientsHaving

// ConcreteComponent
struct SimpleCoffee: BeverageDataHaving {
    // operation
    let cost: Double = 1.0
    let ingredients = ["Water", "Coffee"]
}

// Decorator
protocol BeverageHaving: BeverageDataHaving {
    // component
    var beverage: BeverageDataHaving { get }
}

// ConcreteDecorator
struct Milk: BeverageHaving {
    // component
    let beverage: BeverageDataHaving
    // operation
    var cost: Double {
        return beverage.cost + 0.5
    }
    // operation
    var ingredients: [String] {
        return beverage.ingredients + ["Milk"]
    }
}

// ConcreteDecorator
struct WhipCoffee: BeverageHaving {
    // component
    let beverage: BeverageDataHaving
    // operation
    var cost: Double {
        return beverage.cost + 0.5
    }
    // operation
    var ingredients: [String] {
        return beverage.ingredients + ["Whip"]
    }
}


// usage //
// 型推論に任せずに明示的に型を決定している。これによって、MilkもWhipCoffeeも同等に扱えるようにしている。
var someCoffee: BeverageDataHaving = SimpleCoffee()
print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)")
someCoffee = Milk(beverage: someCoffee)
print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)")
someCoffee = WhipCoffee(beverage: someCoffee)
print("Cost: \(someCoffee.cost); Ingredients: \(someCoffee.ingredients)")
```

# クラス図との対応
|  サンプルコード  |  クラス図  |
| ---- | ---- |
|  **CostHaving** |  **Component**  |
|  cost  |  operation  |

|  サンプルコード  |  クラス図  |
| ---- | ---- |
|  **IngredientsHaving** |  **Component**  |
|  ingredients  |  operation  |

|  サンプルコード  |  クラス図  |
| ---- | ---- |
|  **BeverageDataHaving** |  **Component**  |

|  サンプルコード  |  クラス図  |
| ---- | ---- |
|  **SimpleCoffee**  |  **ConcreteComponent**  |
|  cost, ingredients  |  operation  |

|  サンプルコード  |  クラス図  |
| ---- | ---- |
|  **BeverageHaving**  |  **Decorator**  |
|  beverage  |  Component  |

|  サンプルコード  |  クラス図  |
| ---- | ---- |
|  **Milk**, **WhipCoffee**  |  **ConcreteDecorator**  |
|  beverage  |  component  |
|  cost, ingredients  |  operation  |


# 考察
`SimpleCoffe`（`ConcreteComponent`）と`Milk/WhipCoffe`（`ConcreteDecorator`）に対して同じプロトコル`BeverageDataHaving`（`Component`）に準拠させ、`cost`/`indredients`（`operation`）という同一メソッドの実行時の振る舞いを変えている（**ポリモーフィズム**）。
`someCoffee`は、はじめは`SimpleCoffee`のイニシャライザで生成され、その後、`Milk`、`WhipCoffee`のイニシャライザで置き換えられているが、`BeverageDataHaving`型として[アップキャスト](https://qiita.com/moccow/items/13a9232df69929ca4ae2)されているので、すべて同じ型として扱うことができる。
また、`Milk`、`WhipCoffee`ともに`beverage`を持つことで（**集約**）、デフォルトの値を参照している。