Builder パターン とは
概要
「Builder」を直訳すると「建築者」という意味です。
プログラミングにおいては、インスタンスの生成を担う「建築者」と捉える事ができます。
Wikipediaによると
オブジェクトの生成過程を抽象化することによって、動的なオブジェクトの生成を可能にする。
SwiftにおけるBuilder パターン
インスタンス生成時に、多くの引数をinit
に渡すため、気づいたらコードが冗長化して見づらくなっているということが自分の中ではあるあるパターンです。
Swiftにおいては、デフォルト引数という仕組みがありますが、使いすぎるとインスタンス初期化時にゴチャゴチャします。
なので、そんな時は、Builderパターン
の採用を考えてみてもいいかもと思います。
実装例
今回は、「とあるカフェで自分で組み合わせるオリジナルの飲み物をつくる」という状況を例にして考えます。
仕様は以下のようにします。
インスタンスを生成するときに、以下のパラメーターを渡してオリジナルの飲み物を作ります。
プロパティ | 必須? | 例 | デフォルト値 |
---|---|---|---|
baseDrink | ◯ | コーヒー、紅茶、ジュース | - |
size | ◯ | S、M、L | - |
topping | - | なし、ナタデココ、タピオカ | なし |
inMilk | - | - | false |
ice | - | なし、バニラ、チョコ | なし |
最後に、生成されたインスタンス(オリジナルドリンク)の価格を計算します。
Sample Code
class OriginalDrinkBuilder {
let baseDrink: BaseDrink
let size: DrinkSize
private(set) var topping: Topping = .none
private(set) var inMilk = false
private(set) var iceCream: IceCream = .none
init(baseDrink: BaseDrink, size: DrinkSize) {
self.baseDrink = baseDrink
self.size = size
}
func addTopping(_ topping: Topping) -> Self {
self.topping = topping
return self
}
func setInMilk(_ flag: Bool) -> Self {
self.inMilk = flag
return self
}
func addIceCream(_ flavor: IceCream) -> Self {
self.iceCream = flavor
return self
}
func build() -> OriginalDrink {
let drink = OriginalDrink(baseDrink: baseDrink, size: size)
drink.topping = topping
drink.inMilk = inMilk
drink.iceCream = iceCream
return drink
}
}
class OriginalDrink {
let baseDrink: BaseDrink
let size: DrinkSize
var topping: Topping = .none
var inMilk = false
var iceCream: IceCream = .none
init(baseDrink: BaseDrink, size: DrinkSize) {
self.baseDrink = baseDrink
self.size = size
}
func account() -> Int {
// NOTE: 会計
return baseDrink.rawValue + size.rawValue + topping.rawValue + iceCream.rawValue + (inMilk ? 50 : 0)
}
}
// used
let drink = OriginalDrinkBuilder(baseDrink: .coffee, size: .M)
.addTopping(.tapioca)
.setInMilk(true)
.addIceCream(.vanilla)
.build()
print("\(drink.account())円")
参考にしたサイト
実践で使うならきっとこんな感じだと思います。