[iOS 8] Swiftでデザインパターン No.10 Builder

2015.04.13

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Builder

Builder とは

英単語 Build には以下のような意味があります。

  • 組み立てる
  • 建築する

Builder パターンは、オブジェクトの生成過程を抽象化することによって、動的なオブジェクトの生成を可能にするパターンです。

クラス図

builder

ポイント

  • 抽象クラス Builder の buildPart オペレーションはデフォルトでは何も行わない
  • 各 ConcreteBuilder クラスが、生成する構成要素に対するオペレーションのみをオーバーライドする

サンプルコード

今回は「勇者」オブジェクトを生成し、以下の項目を設定するプログラムを考えてみました。

  • レベル
  • ぶき
  • よろい

Builder

class Builder: NSObject {
func buildLevel(level: Int) {}
func buildSword(sword: String) {}
func buildArmor(armor: String) {}
}

こちらは Builder クラスです。 「レベル」、「ぶき」、「よろい」を設定するメソッドを持っています。

HeroBuilder

class HeroBuilder: Builder {

let hero = Hero()

override func buildLevel(level: Int) {
self.hero.level = level
}

override func buildSword(sword: String) {
self.hero.sword = sword
}

override func buildArmor(armor: String) {
self.hero.armor = armor
}

func getResult() -> Hero {
return self.hero
}
}

こちらは ConcreteBuilder クラスです。 「勇者」オブジェクトを構築するクラスです。

Hero

class Hero: NSObject {

var level: Int?
var sword: String?
var armor: String?

func showStatus() {
println("### Status ###")
println("Level: (self.level)")
println("Sword: (self.sword)")
println("Armor: (self.armor)")
println("##############")
}

func checkStatus() {
if let level = self.level, sword = self.sword, armor = self.armor where level > 10 {
println("そなたは もう じゅうぶんにつよい!")
} else {
println("レベルが あがったら また くるがいい")
println("ぶきや ぼうぐは そうびしないと いみがないぞ")
}
}
}

こちらは Product クラスです。 「勇者」を表します。 ステータスを表示するメソッド、ステータスをチェックするメソッドを持ちます。

Director

class Director: NSObject {

let builder: Builder

init(builder: Builder) {
self.builder = builder
}

func construct() {
self.builder.buildLevel(30)
self.builder.buildSword("おうじゃのけん")
self.builder.buildArmor("ひかりのよろい")
}
}

こちらは Director クラスです。 Builder クラスのインタフェースを使って「勇者」を生成します。

実行

let heroBuilder = HeroBuilder()
let director = Director(builder: heroBuilder)
director.construct()

let hero = heroBuilder.getResult()
hero.showStatus()
hero.checkStatus()

実行結果

### Status ###
Level: Optional(30)
Sword: Optional("おうじゃのけん")
Armor: Optional("ひかりのよろい")
##############
そなたは もう じゅうぶんにつよい!

オブジェクトを一度に作成するパターンとは違い、Builder パターンでは Product オブジェクトを段階的に作成します。 これにより Product オブジェクトの内部構造を、より細かくコントロールすることができるようになります。

余裕があれば、装備に「たて」や「かぶと」、キャラクターに「戦士」や「魔法使い」が追加された時についても考えてみましょう。

Multiple Optional Bindings

Hero クラスに無理やり作成した以下のメソッドに注目してください。

func checkStatus() {
if let level = self.level, sword = self.sword, armor = self.armor where level > 10 {
println("そなたは もう じゅうぶんにつよい!")
} else {
println("レベルが あがったら また くるがいい")
println("ぶきや ぼうぐは そうびしないと いみがないぞ")
}
}

ここでは Optional Bindings を使用していますが、Swift 1.2 からは複数の変数について一行の if 文で書けるようになりました。 ネストが深くなることがなくなるので、これは嬉しい進化ですね。(右に長くなってはしまいますが・・・)

まとめ

  • Swift 1.2 からは複数の Optional Bindings に対応した!
  • バインドした変数について条件式も同時に書ける!

リンク