Tbpgr Blog

Ruby プログラマ tbpgr(てぃーびー) のブログ

Ruby | Collecting Inputs | Yield a parameter builder object

概要

Yield a parameter builder object

前提

Confident Rubyではメソッド内の処理を次のように分類しています。
・Collecting Inputs(引数チェック、変換など)
・Performing Work(主処理)
・Delivering Output(戻り値に関わる処理)
・Handling Failure(例外処理)

当記事は上記のうち、Collecting Inputsに関する話です。

詳細

状況

オブジェクトへのパラメータのバインドの結果として、
クライアントは多くの異なるクラス利用のAPIを知らなければならない。

概要

パラメータオブジェクトの初期化を隠ぺいし、
parameter objectやparameter builder objectをyieldする。

理由

builder-baseのインターフェースは複雑なオブジェクト生成のために親しみやすいフロントエンドを提供する。
同時に、安定しているAPIを保つために実装とインターフェースを分けられる。

サンプルコード仕様

色と濃さを指定して文字を書くメソッド(write_by_pencil)を実装します。
引数は、
・色・文字
・ペンスタイルオブジェクト(PencilStyle)
のどちらかを受け取ります。

仕様追加によりペンスタイルオブジェクトがペン種別(シャーペン、ボールペン、サインペンなど)を持てるようになりました。
可能なら write_by_pencil のインターフェースを変更するのが利用ですが、このメソッドはすでに広く利用されており
デグレードの可能性も大きいことからインターフェースを変更したくありません。

そこで、本処理の直前でペンスタイルオブジェクト(PencilStyle)をyieldすることで、
インターフェースを変えないままペン種別を利用可能にします。

サンプルコード(その1)

仕様追加前。

class PencilStyle
  attr_reader :color, :deapth
  def initialize(color, deapth)
    @color, @deapth = color, deapth
  end
end

def write_by_pencil(color_or_pencil_style, deapth = :not_use_deapth)
  pencil_style = color_or_pencil_style.is_a?(String) ? PencilStyle.new(color_or_pencil_style, deapth) : color_or_pencil_style
  "#{pencil_style.color}色、濃さ#{pencil_style.deapth}で文字を書きました。"
end

pencil_style1 = PencilStyle.new("", "B")
pencil_style2 = PencilStyle.new("", "HB")

puts write_by_pencil("", "3B")
puts write_by_pencil(pencil_style1)
puts write_by_pencil(pencil_style2)

出力

黄色、濃さ3Bで文字を書きました。
赤色、濃さBで文字を書きました。
緑色、濃さHBで文字を書きました。

サンプルコード(その2)

仕様追加後。引数は変更せずブロックによって新規パラメータを設定可能にしています。

class PencilStyle
  attr_reader :color, :deapth
  def initialize(color, deapth, type = "鉛筆")
    @color, @deapth, @type = color, deapth, type
  end

  def type
    @type
  end

  def type=(type)
    @type = type
  end
end

def write_by_pencil(color_or_pencil_style, deapth = :not_use_deapth)
  pencil_style = color_or_pencil_style.is_a?(String) ? PencilStyle.new(color_or_pencil_style, deapth) : color_or_pencil_style
  yield(pencil_style) if block_given?
  "#{pencil_style.color}色の#{pencil_style.type}で濃さ#{pencil_style.deapth}の文字を書きました。"
end

pencil_style1 = PencilStyle.new("", "B")
pencil_style2 = PencilStyle.new("", "HB", "ボールペン")

ret = write_by_pencil("", "3B") do |pencil_style|
  pencil_style.type = ""
end
puts ret
ret = write_by_pencil(pencil_style1)
puts ret
ret = write_by_pencil(pencil_style1) do |pencil_style|
  pencil_style.type = "シャーペン"
end
puts ret
ret = write_by_pencil(pencil_style2)
puts ret
ret = write_by_pencil(pencil_style2) do |pencil_style|
  pencil_style.type = "蛍光ペン"
end
puts ret

出力

黄色の筆で濃さ3Bの文字を書きました。
赤色の鉛筆で濃さBの文字を書きました。
赤色のシャーペンで濃さBの文字を書きました。
緑色のボールペンで濃さHBの文字を書きました。
緑色の蛍光ペンで濃さHBの文字を書きました。