Tbpgr Blog

Employee Experience Engineer tbpgr(てぃーびー) のブログ

Ruby | Proxy Pattern 〜 CodeIQの簡単な問題は後輩Proxyに解かせる

概要

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