概要
Call back instead of returning
前提
Confident Rubyではメソッド内の処理を次のように分類しています。
・Collecting Inputs(引数チェック、変換など)
・Performing Work(主処理)
・Delivering Output(戻り値に関わる処理)
・Handling Failure(例外処理)
当記事は上記のうち、Delivering Outputに関する話です。
詳細
状況
クライアントコードは、メソッドがシステムに変化を与えたかどうかで
アクションを切り替える必要があるかもしれない。
概要
戻り値よりも完了を条件付きのblockへyieldする
理由
完了時のコールバックはtrue・falseを返却するより意味深い。
サンプルコード仕様
アンパンマンのガチャガチャを扱います。
欲しいキャラクター名を指定し、該当するキャラクターが取得出来た時のみ
自由に処理を切り替えられるようにしたいです。
サンプル1:欲しいおもちゃだったかどうかtrue,falseで返却
サンプル1:欲しいおもちゃだった場合にブロックを実行できるようにする
補足
true, falseでの返却はCommand/Query Separationの原則(コマンド・クエリー分離原則)に反する場合があります。
つまりクラスの状態を変化させつつ、その結果を返却するということです。
コマンド=状態(値)を変化させる
クエリ=状態(値)を返却する
を守ることで、利用者の驚きを最小化する設計になります。
サンプルコード(適用前)
class AnpanmanCapsuleToy ANPANMAN = "アンパンマン" BAIKINMAN = "バイキンマン" DOKIN = "ドキンちゃん" CAPSULES = [ANPANMAN, BAIKINMAN, DOKIN, DOKIN] def choise_capsule(want_toy) toy = choise_random_toy CAPSULES.delete toy if toy == want_toy true else false end end private def choise_random_toy case rand(3) when 1 ANPANMAN when 2 BAIKINMAN else DOKIN end end end ap = AnpanmanCapsuleToy.new ret = ap.choise_capsule AnpanmanCapsuleToy::ANPANMAN if ret puts "欲しかった#{AnpanmanCapsuleToy::ANPANMAN}を手に入れた" else puts "#{AnpanmanCapsuleToy::ANPANMAN}が手に入らなかったのでもう一回チャレンジ" ap.choise_capsule AnpanmanCapsuleToy::ANPANMAN end
出力1
欲しかったアンパンマンを手に入れた
出力2
アンパンマンが手に入らなかったのでもう一回チャレンジ
サンプルコード(適用後)
class AnpanmanCapsuleToy ANPANMAN = "アンパンマン" BAIKINMAN = "バイキンマン" DOKIN = "ドキンちゃん" CAPSULES = [ANPANMAN, BAIKINMAN, DOKIN, DOKIN] def choise_capsule(want_toy, choise_toy_callback = -> (x){}, not_choise_toy_callback = ->(x){}) toy = choise_random_toy CAPSULES.delete toy if toy == want_toy choise_toy_callback.call(want_toy) else not_choise_toy_callback.call(want_toy) end end private def choise_random_toy case rand(3) when 1 ANPANMAN when 2 BAIKINMAN else DOKIN end end end ap = AnpanmanCapsuleToy.new ret = ap.choise_capsule AnpanmanCapsuleToy::ANPANMAN, -> (want_toy) { puts "欲しかった#{want_toy}を手に入れた" }, -> (want_toy) { puts "#{AnpanmanCapsuleToy::ANPANMAN}が手に入らなかったのでもう一回チャレンジ" ap.choise_capsule AnpanmanCapsuleToy::ANPANMAN }
出力1
欲しかったアンパンマンを手に入れた
出力2
アンパンマンが手に入らなかったのでもう一回チャレンジ
参照
Martin FowlerのCommandQuerySeparation
http://martinfowler.com/bliki/CommandQuerySeparation.html