概要
Represent failure with a special case object
前提
Confident Rubyではメソッド内の処理を次のように分類しています。
・Collecting Inputs(引数チェック、変換など)
・Performing Work(主処理)
・Delivering Output(戻り値に関わる処理)
・Handling Failure(例外処理)
当記事は上記のうち、Delivering Outputに関する話です。
詳細
状況
クエリーメソッドがいつも値を見つけることができるとは限らない
概要
nilの代わりに特別なオブジェクトを返却する。
例えばウェブサイトの匿名ユーザーの訪問へのGuestUserの返却が代表的です。
理由
特別なオブジェクトはnilチェックを避け、通常のオブジェクトと同様に安全に代役として動作します。
サンプルコード仕様
Programmersクラス、Programmerクラスを作成します。
ProgrammersはProgrammerクラスの配列をメンバに持ちます。
Programmerクラスはnameメンバを持ち、programmingを振る舞いに持ちます。
Programmersが保持していないProgrammerはエセプログラマ(PseudoProgrammer)とします。
彼らはプログラマの不利をしていますがプログラミングができません。
サンプル1ではProgrammersに対象が含まれていない場合はnilを返却しています。
この場合、以降の処理で都度nilチェックによる分岐が必要です。
サンプル2ではProgrammersに対象が含まれていない場合はPseudoProgrammerクラスを返却しています。
この場合、以降の処理では通常のProgrammerクラスと同様の処理が可能となり分岐が不要になります。
サンプルコードその1
class Programmers attr_reader :programmers def initialize(programmers) @programmers = programmers end end class Programmer attr_reader :name def initialize(name) @name = name end def programming "#{@name} is programming.." end end programmers = Programmers.new([Programmer.new('tanaka'), Programmer.new('sato')]) ['tanaka', 'sato', 'suzuki'].each do |person| programmer = if programmers.programmers.any? { |v|v.name == person } programmers.programmers.find { |v|v.name == person } end if programmer puts programmer.programming else puts "#{person} can not programming(he/she is pseudo programming)" end end
出力
tanaka is programming.. sato is programming.. suzuki can not programming(he/she is pseudo programming)
サンプルコードその2
class Programmers attr_reader :programmers def initialize(programmers) @programmers = programmers end end class Programmer attr_reader :name def initialize(name) @name = name end def programming "#{@name} is programming.." end end class PseudoProgrammer attr_reader :name def initialize(name) @name = name end def programming "#{@name} can not programming(he/she is pseudo programming)" end end programmers = Programmers.new([Programmer.new('tanaka'), Programmer.new('sato')]) ['tanaka', 'sato', 'suzuki'].each do |person| programmer = if programmers.programmers.any? { |v|v.name == person } programmers.programmers.find { |v|v.name == person } else PseudoProgrammer.new(person) end puts programmer.programming end
出力
tanaka is programming.. sato is programming.. suzuki can not programming(he/she is pseudo programming)