Tbpgr Blog

Ruby プログラマ tbpgr(てぃーびー) のブログ

RubyでProxyパターン/Matzは松江から来るのに時間がかかるのでProxyRubyistを置く!(Forwardable版)

概要

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 = 利用者

UML


実装サンプル

サンプル概要

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:どうやって名前空間の重複を解決するの?
→回答不明