Delegate是一種應用composite來代替extend的機制,可以有效地降低代碼的耦合性。
Rails 2.2增加了delegate方法,可以十分方便地實現delegate機制。來看看源碼吧:
def delegate(*methods) options = methods.pop unless options.is_a?(Hash) && to = options[:to] raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, :to => :greeter)." end if options[:prefix] == true && options[:to].to_s =~ /^[^a-z_]/ raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method." end prefix = options[:prefix] && "#{options[:prefix] == true ? to : options[:prefix]}_" methods.each do |method| module_eval(<<-EOS, "(__DELEGATION__)", 1) def #{prefix}#{method}(*args, &block) #{to}.__send__(#{method.inspect}, *args, &block) end EOS endend
delegate方法首先檢查傳入的參數,正確參數形式為:method1, :method2, ..., :methodN, :to => klass[, :prefix => prefix]
delegate要求參數的最後必須是一個Hash,:to表示需要代理的類,:prefix表示代理的方法是否要加首碼,如果:prefix
=> true,則代理的方法名為klass_method1, klass_method2, ...,
klass_methodN,如果:prefix => prefix
(prefix為string),則代理的方法名為prefix_method1, prefix_method2, ...,
prefix_methodN。
最終通過module_eval動態產生每個方法定義。通過send方法調用:to類的方法。
來看看調用的例子:
簡單的調用:
class Greeter ActiveRecord::Base def hello() "hello" end def goodbye() "goodbye" endendclass Foo ActiveRecord::Base delegate :hello, :goodbye, :to => :greeterendFoo.new.hello # => "hello"Foo.new.goodbye # => "goodbye"
增加:prefix = true:
class Foo ActiveRecord::Base delegate :hello, :goodbye, :to => :greeter, :prefix => trueendFoo.new.greeter_hello # => "hello"Foo.new.greeter_goodbye # => "goodbye"
自訂首碼名:
class Foo ActiveRecord::Base delegate :hello, :goodbye, :to => :greeter, :prefix => :fooendFoo.new.foo_hello # => "hello"Foo.new.foo_goodbye # => "goodbye"
ruby的動態性再一次發揮了強大的功能!