概要
GoFのデザインパターンのProxyパターンについて。
ある処理について、代理人を置くことで処理を分散して負荷を軽減させる。
登場人物
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 require_relative './rubyist' =begin rdoc = RubyQuestionerクラス =end class RubyQuestioner attr_accessor :rubyist def initialize(rubyist) @rubyist = rubyist end def ask_easy_question puts "#{self.class}:どうやって文字を出力するの?" @rubyist.answer_easy_question end def ask_normal_question puts "#{self.class}:どうやってクラスを作成するの?" @rubyist.answer_normal_question end def ask_difficult_question puts "#{self.class}:どうやって名前空間の重複を解決するの?" @rubyist.answer_difficult_question end end
# encoding: Shift_JIS =begin rdoc = Rubyistクラス =end class Rubyist attr_accessor :rubyist_map LEVEL_BEGGINER="begginer" LEVEL_NORMAL="normal" LEVEL_MASTER="mater" NOT_OVERRRIDE = 'not override error' def initialize(rubyist_map=nil) raise NOT_OVERRRIDE end def answer_easy_question() raise NOT_OVERRRIDE end def answer_normal_question() raise NOT_OVERRRIDE end def answer_difficult_question() raise NOT_OVERRRIDE end end
BeginnerRubyist
# encoding: Shift_JIS =begin rdoc = BeginnerRubyistクラス =end class BeginnerRubyist def initialize(rubyist_map=nil) @rubyist_map=rubyist_map end def answer_easy_question() puts "→#{self.class}:答えはputsだよ" end def answer_normal_question() if @rubyist_map[Rubyist::LEVEL_NORMAL] @rubyist_map[Rubyist::LEVEL_NORMAL].answer_normal_question elsif @rubyist_map[Rubyist::LEVEL_MASTER] @rubyist_map[Rubyist::LEVEL_MASTER].answer_normal_question else puts "→#{self.class}:分かりません" end end def answer_difficult_question() if @rubyist_map[Rubyist::LEVEL_MASTER] @rubyist_map[Rubyist::LEVEL_MASTER].answer_difficult_question else puts "→#{self.class}:分かりません" end end end
NormalRubyist
# encoding: Shift_JIS =begin rdoc = NormalRubyistクラス =end class NormalRubyist def initialize(rubyist_map=nil) @rubyist_map=rubyist_map end def answer_easy_question() puts "→#{self.class}:答えはputsだよ" end def answer_normal_question() puts "→#{self.class}:答えはclassだよ" end def answer_difficult_question() if @rubyist_map[Rubyist::LEVEL_MASTER] @rubyist_map[Rubyist::LEVEL_MASTER].answer_difficult_question else puts "→#{self.class}:分かりません" end end end
Matz
# encoding: Shift_JIS =begin rdoc = Matzクラス =end class Matz def initialize(rubyist_map=nil) @rubyist_map=nil end def answer_easy_question() puts "→#{self.class}:答えはputsだよ" end def answer_normal_question() puts "→#{self.class}:答えはclassだよ" end def answer_difficult_question() puts "→#{self.class}:答えはModuleだよ" end end
main
# encoding: Shift_JIS require_relative './ruby_questioner' require_relative './rubyist' require_relative './beginner_rubyist' require_relative './normal_rubyist' require_relative './matz' rubyist_map = Hash.new matz = Matz.new normal_rubyist = NormalRubyist.new rubyist_map[Rubyist::LEVEL_NORMAL] = normal_rubyist rubyist_map[Rubyist::LEVEL_MASTER] = matz beginner_rubyist = BeginnerRubyist.new(rubyist_map) puts "−−−−−−−−−−−−−Beginnerが代理人を勤める時−−−−−−−−−−−−−" ruby_questioner = RubyQuestioner.new(beginner_rubyist) ruby_questioner.ask_easy_question ruby_questioner.ask_normal_question ruby_questioner.ask_difficult_question # 以下はMatz不在時 puts "−−−−−−−−−−−−−Matz不在時−−−−−−−−−−−−−" rubyist_map.delete(Rubyist::LEVEL_MASTER) ruby_questioner.ask_easy_question ruby_questioner.ask_normal_question ruby_questioner.ask_difficult_question # 以下はNormalRubyist不在時 puts "−−−−−−−−−−−−−NormalRubyist不在時−−−−−−−−−−−−−" rubyist_map.delete(Rubyist::LEVEL_NORMAL) rubyist_map[Rubyist::LEVEL_MASTER] = matz ruby_questioner.ask_easy_question ruby_questioner.ask_normal_question ruby_questioner.ask_difficult_question # 以下はMatzしかいない時 puts "−−−−−−−−−−−−−Matzしかいない時−−−−−−−−−−−−−" matz = Matz.new ruby_questioner = RubyQuestioner.new(matz) ruby_questioner.ask_easy_question ruby_questioner.ask_normal_question ruby_questioner.ask_difficult_question
出力結果
−−−−−−−−−−−−−Beginnerが代理人を勤める時−−−−−−−−−−−−− RubyQuestioner:どうやって文字を出力するの? →BeginnerRubyist:答えはputsだよ RubyQuestioner:どうやってクラスを作成するの? →NormalRubyist:答えはclassだよ RubyQuestioner:どうやって名前空間の重複を解決するの? →Matz:答えはModuleだよ −−−−−−−−−−−−−Matz不在時−−−−−−−−−−−−− RubyQuestioner:どうやって文字を出力するの? →BeginnerRubyist:答えはputsだよ RubyQuestioner:どうやってクラスを作成するの? →NormalRubyist:答えはclassだよ RubyQuestioner:どうやって名前空間の重複を解決するの? →BeginnerRubyist:分かりません −−−−−−−−−−−−−NormalRubyist不在時−−−−−−−−−−−−− RubyQuestioner:どうやって文字を出力するの? →BeginnerRubyist:答えはputsだよ RubyQuestioner:どうやってクラスを作成するの? →Matz:答えはclassだよ RubyQuestioner:どうやって名前空間の重複を解決するの? →Matz:答えはModuleだよ −−−−−−−−−−−−−Matzしかいない時−−−−−−−−−−−−− RubyQuestioner:どうやって文字を出力するの? →Matz:答えはputsだよ RubyQuestioner:どうやってクラスを作成するの? →Matz:答えはclassだよ RubyQuestioner:どうやって名前空間の重複を解決するの? →Matz:答えはModuleだよ
参照
RubyでProxyパターン/Matzは松江から来るのに時間がかかるのでProxyRubyistを置く!(Forwardable版)
http://d.hatena.ne.jp/tbpg/20121202/1354463011