概要
Proxy Pattern 〜 CodeIQの簡単な問題は後輩Proxyに解かせる
詳細
Proxy Patternは、生成コストが大きかったり・何らかの前処理や後処理をする領域がほしかったりする場合に
本物のオブジェクトのふりをするオブジェクトを作成するパターンです。
これにより、
・毎回本物のオブジェクトに問い合わせる必要のない処理をProxyで処理して負荷を軽減する
・対象オブジェクトの責務とは別に新たに追加したい前処理や後処理を個別の呼び出し箇所にばらばらに実装せず、
Proxyにまとめて実装して、DRYに管理できる。
となどが可能になります。
サンプル仕様1
CodeIQの解答者を想定します。
この解答者さんは、めんどくさがりのため簡単に解けることが明白な問題は
後輩に解かせることにしました。
※本当にやったら規約違反なのでご注意ください
サンプル1_1は自分で全ての問題を解く場合のコード。
サンプル1_2は後輩をProxyとして用意して、簡単な問題を解かせる場合のコードです。
サンプル1_1
自分で全て問題を解いていた頃のコード
require 'attributes_initializable' class LazySolver include AttributesInitializable attr_reader_init :name def solve(problem) "#{@name} solve rank #{problem.difficulty} problem" end end class Problem include AttributesInitializable attr_reader_init :difficulty end [*1..4].each do |difficulty| puts LazySolver.new({name: 'lazy solver'}).solve(Problem.new({difficulty: difficulty})) end __END__ AttributesInitializableは tbpgr_utils gemの機能です。 AttributesInitializableのincludeとattr_accessor_initで attr_accessorの宣言とコンストラクタでのメンバへの変数設定を一気にやっていると思ってください。 tbpgr_utils gemについては下記参照 https://github.com/tbpgr/tbpgr_utils
出力
lazy solver solve rank 1 problem lazy solver solve rank 2 problem lazy solver solve rank 3 problem lazy solver solve rank 4 problem
サンプル1_2
require 'attributes_initializable' class LazySolver include AttributesInitializable attr_reader_init :name def solve(problem) "#{@name} solve rank #{problem.difficulty} problem" end end class BeginnerProgrammer include AttributesInitializable attr_reader_init :name def solve(problem) case problem.difficulty when 1, 2 "#{@name} solve rank #{problem.difficulty} problem" when 3, 4 LazySolver.new({name: 'lazy'}).solve(problem) end end end class Problem include AttributesInitializable attr_reader_init :difficulty end [*1..4].each do |difficulty| puts BeginnerProgrammer.new({name: 'beginner solver'}).solve(Problem.new({difficulty: difficulty})) end __END__ AttributesInitializableは tbpgr_utils gemの機能です。 AttributesInitializableのincludeとattr_accessor_initで attr_accessorの宣言とコンストラクタでのメンバへの変数設定を一気にやっていると思ってください。 tbpgr_utils gemについては下記参照 https://github.com/tbpgr/tbpgr_utils
出力
beginner solver solve rank 1 problem beginner solver solve rank 2 problem lazy solve rank 3 problem lazy solve rank 4 problem
サンプル仕様2
CodeIQの解答者を想定します。
この解答者さんは、めんどくさがりのためCodeIQに関わる様々な
作業のうち簡単にできるものやログインなどが不要なものを後輩にやらせることにしました。
CodeIQのサイトをチェックする=>後輩
問題のヒントになりそうなサイトから情報収集をする=>後輩
問題を解く=>自分
問題を送信する=>自分
問題を解いた結果をツイートする=>自分
サンプル2_1は自分で作業を行う場合のコード。
サンプル2_2は後輩をProxyとして用意して、様々な作業をさせる場合のコード。
委譲のコードを大量に書くことを避けるために method_missing を利用します。
サンプル2_1
require 'attributes_initializable' class LazySolver include AttributesInitializable attr_reader_init :name def solve(problem) "'#{@name}' solve rank #{problem.difficulty} problem" end def search_hint_from_web(problem) "'#{@name}' search rank #{problem.difficulty} problem's hint from web" end def check_codeiq_web "'#{@name}' check_codeiq_web" end def submit_answer(problem) "'#{@name}' submit rank #{problem.difficulty} problem answer" end def tweet_about_codeiq(problem) "'#{@name}' I solve rank #{problem.difficulty} problem now" end end class Problem include AttributesInitializable attr_reader_init :difficulty end lazy_solver = LazySolver.new({name: 'lazy solver'}) puts lazy_solver.check_codeiq_web [1, 2].each do |difficulty| problem = Problem.new({difficulty: difficulty}) puts lazy_solver.search_hint_from_web(problem) puts lazy_solver.solve(problem) puts lazy_solver.submit_answer(problem) puts lazy_solver.tweet_about_codeiq(problem) end __END__ AttributesInitializableは tbpgr_utils gemの機能です。 AttributesInitializableのincludeとattr_accessor_initで attr_accessorの宣言とコンストラクタでのメンバへの変数設定を一気にやっていると思ってください。 tbpgr_utils gemについては下記参照 https://github.com/tbpgr/tbpgr_utils
'lazy solver' check_codeiq_web 'lazy solver' search rank 1 problem's hint from web 'lazy solver' solve rank 1 problem 'lazy solver' submit rank 1 problem answer 'lazy solver' I solve rank 1 problem now 'lazy solver' search rank 2 problem's hint from web 'lazy solver' solve rank 2 problem 'lazy solver' submit rank 2 problem answer 'lazy solver' I solve rank 2 problem now
サンプル2_2
require 'attributes_initializable' class LazySolver include AttributesInitializable attr_reader_init :name def solve(problem) "'#{@name}' solve rank #{problem.difficulty} problem" end def check_codeiq_web "'#{@name}' check_codeiq_web" end def submit_answer(problem) "'#{@name}' submit rank #{problem.difficulty} problem answer" end def tweet_about_codeiq(problem) "'#{@name}' I solve rank #{problem.difficulty} problem now" end end class BeginnerProgrammer include AttributesInitializable attr_reader_init :name, :senior_programmer def check_codeiq_web "'#{@name}' check_codeiq_web" end def search_hint_from_web(problem) "'#{@name}' search rank #{problem.difficulty} problem's hint from web" end def method_missing(method, *args) respond_to?(method) ? send(method, *args) : @senior_programmer.send(method, *args) end end class Problem include AttributesInitializable attr_reader_init :difficulty end beginner_programmer = BeginnerProgrammer.new({name: 'beginner programmer', senior_programmer:LazySolver.new({name: 'lazy solver'})}) puts beginner_programmer.check_codeiq_web [1, 2].each do |difficulty| problem = Problem.new({difficulty: difficulty}) puts beginner_programmer.search_hint_from_web(problem) puts beginner_programmer.solve(problem) puts beginner_programmer.submit_answer(problem) puts beginner_programmer.tweet_about_codeiq(problem) end __END__ AttributesInitializableは tbpgr_utils gemの機能です。 AttributesInitializableのincludeとattr_accessor_initで attr_accessorの宣言とコンストラクタでのメンバへの変数設定を一気にやっていると思ってください。 tbpgr_utils gemについては下記参照 https://github.com/tbpgr/tbpgr_utils
出力
'beginner programmer' check_codeiq_web 'beginner programmer' search rank 1 problem's hint from web 'lazy solver' solve rank 1 problem 'lazy solver' submit rank 1 problem answer 'lazy solver' I solve rank 1 problem now 'beginner programmer' search rank 2 problem's hint from web 'lazy solver' solve rank 2 problem 'lazy solver' submit rank 2 problem answer 'lazy solver' I solve rank 2 problem now