元ネタ → ochococo/Design-Patterns-In-Swift
クラス図

図の引用元:Wikipedia: Decorator パターン
概要
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クラスのオブジェクトでオブジェクトをラップすることにより、実行時にオブジェクトの機能を拡張または変更するために使用する。継承を使用して動作を変更する代わりに柔軟な方法を提供する。
サンプルコード
// 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型としてアップキャストされているので、すべて同じ型として扱うことができる。
また、Milk、WhipCoffeeともにbeverageを持つことで(集約)、デフォルトの値を参照している。