概要
RubyでProxyパターン/Matzは松江から来るのに時間がかかるのでProxyRubyistを置く!
http://d.hatena.ne.jp/tbpg/20120306/1331048460
の内容をForwardableを利用して書き直しました。
http://www.ruby-lang.org/ja/old-man/html/Forwardable.html
登場人物
Subject = 主体
RealSubject = 主体の実体
Proxy = 代理人
Client = 利用者
実装サンプル
サンプル概要
Rubyに関する質問をしたい人がいます。
この質問者は簡単な質問。普通の質問。難しい質問をします。
回答者となるRubyistには駆け出しRubyist、普通のRubyist、Matzがいます。
回答者の窓口となるのは駆け出しRubyistで、簡単な質問は自分で回答します。
駆け出しRubyistは普通の質問の答えが分からないので
普通のRubyistから答えを聞いて回答します。
駆け出しRubyistや普通のRubyistは難しいの質問の答えが分からないので
松江まで行ってMatzに答えを聞いて回答します。
各Rubyistはレベルが高いほど多忙であるため、駆け出しRubyistが代理人となることで
普通のRubyistやMatszの負荷を軽減することが出来ます。
登場人物
Subject = Rubyist: Rubyの質問に回答するRubyist。主体役
RealSubject = Matz: Rubyの質問になんでも事が出来るRubyの創造神。主体の実体役
RealSubject = NormalRubyist: Rubyの質問に回答する普通のRubyist。主体の実体役
Proxy = BeginnerRubyist: Rubyの質問に回答する駆け出しRubyist。代理人役
Client = RubyQuestioner: Rubyの質問者。利用者役
サンプルコード
RubyQuestioner
# encoding: Shift_JIS =begin rdoc = RubyQuestionerクラス =end class RubyQuestioner attr_accessor :rubyist QUESTION = {"easy"=>"どうやって文字を出力するの?", "normal"=>"どうやってクラスを作成するの?", "difficult"=>"どうやって名前空間の重複を解決するの?"} def initialize(rubyist) @rubyist = rubyist end def ask_question(level) puts "#{self.class}:#{QUESTION[level]}" method_name = "answer_#{level}_question" return @rubyist.method(method_name).call if @rubyist.respond_to?(method_name) puts "→回答不明" end end
BeginnerRubyist
# encoding: Shift_JIS =begin rdoc = BeginnerRubyistクラス =end class BeginnerRubyist def answer_easy_question() puts "→#{self.class}:答えはputsだよ" end end
NormalRubyist
# encoding: Shift_JIS require 'forwardable' require_relative './beginner_rubyist' =begin rdoc = NormalRubyistクラス =end class NormalRubyist extend Forwardable def initialize() @beginner = BeginnerRubyist.new end def answer_normal_question() puts "→#{self.class}:答えはclassだよ" end def_delegator(:@beginner ,:answer_easy_question) end
Matz
# encoding: Shift_JIS require 'forwardable' require_relative './normal_rubyist' =begin rdoc = Matzクラス =end class Matz extend Forwardable def initialize() @normal = NormalRubyist.new @beginner = BeginnerRubyist.new end def answer_difficult_question() puts "→#{self.class}:答えはModuleだよ" end def_delegator(:@normal, :answer_normal_question) def_delegator(:@beginner, :answer_easy_question) end
main
# encoding: Shift_JIS require_relative './ruby_questioner' require_relative './matz' require_relative './normal_rubyist' require_relative './beginner_rubyist' rubyists = [Matz.new, NormalRubyist.new,BeginnerRubyist.new] rubyists.each do |rubyist| puts "--------------------#{rubyist}--------------------" questioner = RubyQuestioner.new(rubyist) %w{easy normal difficult}.each {|level|questioner.ask_question level} end
出力結果
--------------------#<Matz:0x2502d08>-------------------- RubyQuestioner:どうやって文字を出力するの? →BeginnerRubyist:答えはputsだよ RubyQuestioner:どうやってクラスを作成するの? →NormalRubyist:答えはclassだよ RubyQuestioner:どうやって名前空間の重複を解決するの? →Matz:答えはModuleだよ --------------------#<NormalRubyist:0x2502ca8>-------------------- RubyQuestioner:どうやって文字を出力するの? →BeginnerRubyist:答えはputsだよ RubyQuestioner:どうやってクラスを作成するの? →NormalRubyist:答えはclassだよ RubyQuestioner:どうやって名前空間の重複を解決するの? →回答不明 --------------------#<BeginnerRubyist:0x2502c78>-------------------- RubyQuestioner:どうやって文字を出力するの? →BeginnerRubyist:答えはputsだよ RubyQuestioner:どうやってクラスを作成するの? →回答不明 RubyQuestioner:どうやって名前空間の重複を解決するの? →回答不明