この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
Decorator
Decorator とは
英単語 Decorator には以下のような意味があります。
- 装飾者
Decorator パターンは、既存のオブジェクトに新しい機能や振る舞いを動的に追加することができるパターンです。
クラス図
ポイント
- Decorator と Component は集約の関係
- Decorator は Component のインスタンスをメンバ変数として持つ
サンプルコード
例:カレーに色々トッピング
Menu(Component に対応する)
class Menu {
func getPrice() -> Int {
fatalError("must be overridden")
}
}
operation() メソッドとして、メニューの価格を取得する getPrice() メソッドを定義します。
Curry(ConcreteComponent に対応する)
class Curry: Menu {
override func getPrice() -> Int {
return 390
}
}
カレーの価格は 390 円とします。
Topping(Decorator に対応する)
class Topping: Menu {
let menu: Menu
init(_ menu: Menu) {
self.menu = menu
}
}
Menu クラスのインスタンスをメンバ変数として保持します。 「_(アンダースコア)」については後述します。
CheeseTopping(ConcreteDecorator に対応する)
class CheeseTopping: Topping {
override func getPrice() -> Int {
return menu.getPrice() + 100
}
}
チーズトッピングの価格は 100 円とします。
ChickenTopping(ConcreteDecorator に対応する)
class ChickenTopping: Topping {
override func getPrice() -> Int {
return menu.getPrice() + 200
}
}
チキントッピングの価格は 200 円とします。
HamburgTopping(ConcreteDecorator に対応する)
class HamburgTopping: Topping {
override func getPrice() -> Int {
return menu.getPrice() + 300
}
}
ハンバーグトッピングの価格は 300 円とします。
実行
let price = HamburgTopping(ChickenTopping(CheeseTopping(Curry()))).getPrice()
println("Total price is (price) yen!")
実行結果
Total price is 990 yen!
カレーにチーズとチキンとハンバーグをデコレート(トッピング)して合計価格を出力するプログラムでした。
Decorator パターンを利用することで、プログラム実行時に動的に機能拡張を行うことができます。
謎の文字「_」
「_」はイニシャライザで外部引数名を表示したくない時に使用するシンボルです。
外部引数名については、前回のStrategy パターンを御覧ください。
イニシャライザでは外部引数名が自動で設定されます。 そのままですと、
let price = HamburgTopping(ChickenTopping(CheeseTopping(Curry()))).getPrice()
上記のコードは下記のように書かなければならなくなります。
let price = HamburgTopping(menu: ChickenTopping(menu: CheeseTopping(menu: Curry()))).getPrice()
これは少し見づらいので、ここでは「_」を利用して外部引数名を使わないように設定しました。
init(_ menu: Menu) {
self.menu = menu
}
まとめ
- イニシャライザで外部引数名を表示させたくない時は「_」を利用する