2019-05-14
Rubyによるデザインパターン - builder
[](http://www.amazon.co.jp/exec/obidos/ASIN/4894712857/hatena- blog-22/)
利用する場面
オブジェクトを構成するために大量のコードが必要な場合。
方法
オブジェクトを構成するためのコードをオブジェクト自体から分離し、builder クラスにもたせる。
あれこれ
他のパターンとの違いについて
factory は、決まりきった一式のオブジェクトを生成するときに適用する。(こっちのオブジェクトは a,b,c というインスタンスをつくる、といった具合に。)
builder は、様々なパターンのオブジェクトを煩雑なオプションによって生成するときに適用する。(こっちのオブジェクトは a,b,c というインスタンスをつくり、こっちは a’,b”,c,d をつくる、といった具合に。)
以下の例えが大いに理解を助けてくれたと感じた。
「ハーディーズ(Hardee’s: 米国のレストランチェーン)で何か注文するところを考えます。たとえば『ビッグハーディ』を頼めば、店の人は何も聞かずに持ってきます。これだと simple factory の例になります。しかしたとえば、少し凝ったサブウェイ風のが欲しい場合、[保存版]人間が読んで理解できるデザインパターン解説#1: 作成系(翻訳))
また、書籍に記載されたサンプルコードでいえばだが、以下の点も違いとして見受けられた。
- factory の場合には、インスタンスを持つ。
- builder の場合には、HogeBuilder インスタンスを持つ。
まあこれは本質的な違いではなく、サンプルコードがたまたまそうなったというだけの話で、どちらの方法もありうるのではないかと思う。
サンプル
class Jiro
attr_accessor :abura, :yasai, :karame
end
class JiroBuilder
attr_reader :jiro
def initialize
@jiro = Jiro.new
end
def add_abura(order = :hutsuu)
@jiro.abura = Abura.new(order)
end
def add_yasai(order = :hutsuu)
@jiro.yasai = Yasai.new(order)
end
def add_karame(order = :hutsuu)
@jiro.karame = Karame.new(order)
end
end
class Topping
def initialize(order)
@volume =
case order
when :mashimashi
300
when :mashi
100
when :sukuname
20
else :hutsuu
50
end
end
end
class Abura < Topping ; end
class Yasai < Topping ; end
class Karame < Topping ; end
jb = JiroBuilder.new
jb.add_abura
jb.add_yasai(:mashimashi)
jb.add_karame(:sukuname)
jiro = jb.jiro
p jiro.abura # => #<Abura:0x007fafea957120 @volume=50>
p jiro.yasai # => #<Yasai:0x007fafea9570a8 @volume=300>
p jiro.karame # => #<Karame:0x007fafea957080 @volume=20>
method_missing を利用した magic method というものをやってみる。
JiroBuilder クラスに以下のメソッドを追加する。
def method_missing(name, *args)
words = name.to_s.split("_")
words.each_slice(2) do |topping, order|
send("add_#{topping}", order.to_sym)
end
end
すると、以下のようなことができる。
jb = JiroBuilder.new
jb.abura_mashi_yasai_sukuname_karame_mashimashi
jiro = jb.jiro
p jiro.abura # => #<Abura:0x007f8fe605d6d8 @volume=100>
p jiro.yasai # => #<Yasai:0x007f8fe605d610 @volume=20>
p jiro.karame # => #<Karame:0x007f8fe605d570 @volume=300>
おおー。たのしい。