2010-08-20 50 views
5

我试图做一个代理对象,几乎所有的方法调用转移到子对象,本质上是委托人模式。大多数情况下,我只是使用BasicObject,并将每个调用与method_missing传递给子对象。到现在为止还挺好。愚弄Ruby的大小写运算符===,与代理对象

诀窍是,尽量为我可能,我不能欺骗Ruby的情况下操作,所以我不能做:

x = Proxy.new(15) 
Fixnum === x #=> false, no matter what I do 

这当然使得任何case x操作失败,这意味着代理可以不会安全地交给其他图书馆。

我不能为我的生活弄清楚===正在使用什么。

x.is_a?(Fixnum) #=> true 
x.instance_of?(Fixnum) #=> true 
x.kind_of?(Fixnum) #=> true 
x.class #=> Fixnum 

Module#===只是在做某种神奇的是无法避免的:代理所有基于类的自省,我知道的,这是所有正确地传递到子对象的正常工作?

+0

一句警告:如果您可以通过委派'is_a?','instance_of?','kind_of?','class'等代码将代理伪装为'Fixnum',就可以实现目标!改变这些方法可能会导致你(或者使用/维护你的代码的人)直接调试地狱。 – molf 2010-08-20 07:07:38

回答

1

是的。在C中实现了Module#===,直接检查对象的类层次结构。它看起来不像是有办法愚弄它。

+0

谢谢。这带来了什么不可思议。 – bhuga 2010-08-20 15:54:28

0

我认为你要找的是 Delegator类。

您的代理类应继承Delegator类的子类,然后定义 __getobj____setobj__以获取和设置目标对象。

忘记了,我自己尝试过,它不起作用。

编辑:

由于grddev提到,技术问题是Fixnum对象正在发送的:===方法。但是,我想进一步思考一下,我认为Ruby目前的行为是正确的。由于Delegator应该是一个用于隐藏实现细节的抽象接口,因此Proxy的实例无法正确识别为kind_of? Fixnum对象。

如果您确实希望代理类是一种Fixnum,但希望用方法来修饰它,则要做的逻辑事情是要么派生Fixnum的子类,要么创建ProxyMethods模块并扩展Fixnum的各个实例。

当然,由于您不能真正执行Fixnum.new,所以您必须继承Fixnum的子类才能扩展单个实例,但一般规则就是这样。

+0

只有当您认为程序员不能使用某种形式的对象内省时,技术行为才是正确的,而这种形式似乎存在于C中。不幸的是,此代理需要跟踪任何种类的对象,而不仅仅是Fixnums,所以扩展确实没有帮助(并且由于各种原因,扩展Object也是没有用的)。 – bhuga 2010-08-20 15:56:08

+0

好吧,我明白你的观点。你会希望:===被实现为'发送:instance_of?,MyClass'到你的代理对象,但事实并非如此。我仍然认为,如果你想伪装成一个对象,但想要某种元功能,那么创建一个装饰和跟踪单个对象的Tracking类是一个更好的设计。非单身对象可以被扩展,并且单身实例(例如Fixnum和Symbol)可以被包装和扩展,或者被特殊处理。 – guns 2010-08-20 21:41:20

0

的问题是,它Fixnum === x,这意味着该方法===上调用Fixnum而不是x。您可以替换现有的所有方法(并且注意何时引入新的===方法),但这将是很多工作,并且相当脆弱。

0

您应该可以搜索BlankSlate 类。这个类去掉了一个普通对象的大多数方法,并且该网站有一个简单的Proxy类的例子,它将打印出所有被调用的方法。这可以让你更好地了解正在发生的事情。对不起,我不能给你一个更完整的答案,但我在我的手机上。希望有所帮助。