Decorator
デザインパターンとは
デザインパターンとはオブジェクト思考開発における先人たちが作り上げてきた便利な設計図です。
Gang of Four通称Gofが1994年に出版した『オブジェクト指向における再利用のためのデザインパターン』の中で23個の設計図が紹介されています。
Note
デザインパターンのサンプルコードはSwift4でまとめます。
デコレーターパターンとは?
Decoratorパターンは継承を行わずに既存クラスの動きを修正することのできるパターンです。
特定の1つのクラスとしないため再利用性が高まります。
サンプルコード
サンプルコードではバナナクレープといちごクレープにチョコレートをトッピングするプログラムを作ってみました。
クレーププロトコル
全てのクレープは名前と値段を持っているものであると仮定しています。
protocol Crape {
func getName() -> String
func price() -> Int
}
バナナクレープといちごクレープ
2つのクレープにチョコレートをトッピングしたいと考えた際にそれぞれのクラスを継承してChocolateBananaCrapeクラスとChocolateStrawberyCrapeクラスを作れば実現することは可能です。
しかし、トッピングがチョコだけでなくアイスクリームやホイップクリームが追加されたとしたらどうでしょうか?
class BananaCrape: Crape {
func getName() -> String {
return "バナナクレープ"
}
func price() -> Int {
return 500
}
}
class StrawberryCrape: Crape {
func getName() -> String {
return "いちごクレープ"
}
func price() -> Int {
return 550
}
}
トッピングの分だけクラスを継承して作ることも可能ですが、Decolatorパターンを使い、再利用性を高めることでトッピングやクレープのベースが増えたとしても既存クラスはそのままに対応可能になります。
チョコレートトッピング
class Chocolate: Crape {
private let clape: Crape
init(clape: Crape) {
self.clape = clape
}
func getName() -> String {
return "チョコレート" + self.clape.getName()
}
func price() -> Int {
return 100 + self.clape.price()
}
}
呼び出し元
let bananaCrape = BananaCrape()
let strawberryCrape = StrawberryCrape()
var chocolateTopping = Chocolate(clape: bananaCrape)
print("\(chocolateTopping.getName())は\(chocolateTopping.price())円です")
chocolateTopping = Chocolate(clape: strawberryCrape)
print("\(chocolateTopping.getName())は\(chocolateTopping.price())円です")
コンソール
チョコレートバナナクレープは600円です
チョコレートいちごクレープは650円です
コード一覧
import UIKit
protocol Crape {
func getName() -> String
func price() -> Int
}
class BananaCrape: Crape {
func getName() -> String {
return "バナナクレープ"
}
func price() -> Int {
return 500
}
}
class StrawberryCrape: Crape {
func getName() -> String {
return "いちごクレープ"
}
func price() -> Int {
return 550
}
}
class Chocolate: Crape {
private let clape: Crape
init(clape: Crape) {
self.clape = clape
}
func getName() -> String {
return "チョコレート" + self.clape.getName()
}
func price() -> Int {
return 100 + self.clape.price()
}
}
let bananaCrape = BananaCrape()
let strawberryCrape = StrawberryCrape()
var chocolateTopping = Chocolate(clape: bananaCrape)
print("\(chocolateTopping.getName())は\(chocolateTopping.price())円です")
chocolateTopping = Chocolate(clape: strawberryCrape)
print("\(chocolateTopping.getName())は\(chocolateTopping.price())円です")