Ruby元编程读书笔记六
Dynamic Proxies
可以使用 Ruby 的 delegate 库来快速得到一个实用的 动态代理:
require 'delegate'
class Assistant
def initialize(name)
@name = name
end
def read_email
"(#{@name}) It's mostly spam."
end
def check_schedule
"(#{@name}) You have a meeting today."
end
end
class Manager < DelegateClass(Assistant)
def initialize(assistant)
super(assistant)
end
def attend_meeting
"Please hold my calls."
end
end
DelegateClass() 是一种拟态方法,这种方法创建并返回一个新的 Class。这个类会定义一个 method_missing() 方法,并把对它发生的调用转发到被封装的对象上,比如本例中的 Assistant 对象。Manager 类会继承这个 method_missing() 方法,因此它就成为被封装对象的一个代理。结果, Manager 就会把自己无法识别的方法转发给它封装的 Assistant:
frank = Assistant.new("Frank")
anne = Manager.new(frank)
anne.attend_meeting #=> "Please hold my calls."
anne.read_email #=> "(Frank) It's mostly spam."
anne.check_schedule #=> "(Frank) You have a meeting today."
const_missing()
如果喜欢 Object#method_missing() 方法,则推荐关注 Module#const_missing() 方法。当引用一个不存在的常量时,Ruby 将把这个常量名作为一个符号传递给 const_missing() 方法。
可以在一个给定命名空间中定义 const_missing() 方法。如果在 Object 类中定义它,那么所有的对象(包括最顶层的 main 对象)都会继承这个方法:
def Object.const_missing(name)
name.to_s.downcase.gsub(/_/, ' ')
end
MY_CONSTANT #=> "my constant"
-
使用幽灵方法时经常会出现的问题是,由于调用未定义的方法会导致调用 method_missing() 方法,对象可能会因此接受一个直接的错误方法调用。为了避免这样的困扰,应该仅在必要时才使用幽灵方法。
-
当一个幽灵方法和一个真实方法发生名字冲突时,后者会胜出。如果不需要那个继承来的方法(真实方法),则可以通过删除它来解决这个问题。为了安全起见,应该在代理类中删除绝大多数继承来的方法。这就是所谓的 白板 类(BasicObject),它所拥有的方法比 Object 类还要少。
-
有两种途径来删除一个方法,可以使用 Module#undef_method() 方法,它会删除所有(包括继承来的)的方法;也可以使用 Module#remove_method() 方法,它只会删除接受者自己的方法,而保留继承来的方法。