项目中Delegator的运用来实现偷天换日的能力
Delegator中文名可以叫托管,委托.
在JAVA中是一种比较高深的设计模式.跟继承的思想有一点点像,但远比继承来的灵活.
简单来理解,可以与现实世界来类比,你交给另一个类帮你打点点事件,有点像助理.
这个助理可以帮几个人同时打点事件.也可以自己额外做些事件.
今天在项目中,遇到了一个类似的问题:
以前的代码:
o = M1::M2::Klass.newo.method( :a=> 1 )o.method( :a=> 2 )
#id=>a,name=>参数,type=>s,must=>true,default=>"",value=>"{text}",descrip=>"ok"class Module def const_missing(name) name = self.name.to_s + "::" + name.to_s exception = NameError.new("uninitialized constant #{name}") begin #require File.join(ATT::ConfigureManager.root,'keywords','keyword',name.underscore) load_module(name.to_s) rescue ATT::Exceptions::LoadError raise $! rescue ATT::Exceptions::NotFoundError,Exception raise exception end endendclass Object def self.const_missing(name) exception = NameError.new("uninitialized constant #{name}") begin load_module(name.to_s) rescue ATT::Exceptions::LoadError raise $! rescue ATT::Exceptions::NotFoundError,Exception raise exception end endendM1::M2::Klass.new
def load_module( klass_str ) #前面忽略大量关联加载的代码 #生成Klass instance = eval(klass_str) #转给委托类 keyword_proxy_for_class_name( instance )enddef keyword_proxy_for_class_name( klass ) KeywordProxy.new( klass ) do |m,hash| #处理委托回调代码,这里省略 endend
class KeywordProxy def self.proxy( klass,&block ) # :yields: hash ret_obj = KeywordProxyBase.new( klass.new ) ret_obj.before_call(&block) ret_obj end class << self alias __proxy__ proxy end #对外的委托接口,设置要委托的对象,以及要委托的方法执行前置代码. def initialize( klass, &block ) @klass = klass @block = block class <<self #这里采用匿名方法扩展,使实例化的keyword的类依然支持new,对外代码极其自然 def new KeywordProxy.proxy(@klass, &@block) end end end end class KeywordProxyBase < Delegator def initialize( obj ) @__obj__ = obj #这里不要复制委托的办法,只需回传即可,所以设置为nil super(nil) @before_call_blocks = [] @after_call_blocks = [] end def __getobj__ @__obj__ end def __setobj__(obj) @__obj__ = obj end def before_call(&block) if block @before_call_blocks << block end end def after_call(&block) if block @after_call_blocks << block end end def method_missing(m, *args) # 这里才是真正的回调,某一个方法要执行时,要帮助它执行回调.然后才给它. @before_call_blocks.each do |block| block.call m,*args end ret = super(m,*args) @after_call_blocks.each do |block| block.call ret end ret end end