key 发表于 5-11-2009 13:14:28

The Limitation of Proxy Design Pattern

Assuming you have interfaces and classes as below:

1. interface MyInterface
2. class MyClass implements MyInterface

Now create an Object obj based on MyClass using java.lang.reflect.Proxy or CGList.

Then run some code like:

if(obj instanceof MyClass)
   return true;
else
   return false;

You'll get false.

Why? Here is the code for object creation:

Enhancer e = new Enhancer();
e.setSuperclass(clazz); //clazz == MyInterface.class
e.setCallback(this);
return (T)e.create();

From the class hierarchy's point of view, the new object has nothing to do with MyClass.

key 发表于 5-11-2009 15:39:55

Solution 1:

AntiProxy

1. AntiProxy Interfacepublic interface AntiProxy {
      public Object self();
      public ClassgetOrigClass();
}2. AntiProxyHelperpublic class AntiProxyHelper {
   public static Object invoke(Object obj, Method method, Object[] args){
             Object result = null;
             try{
               result = method.invoke(obj, args); return result;
             }catch(Exception e){}
            
             if(method.getName().equals("self")) return obj;
             else if(method.getName().equals("getOrigClass")) return obj.getClass();
             throw new NoSuchMethodException(method.getName());
   }
   public static boolean instanceOf(Object obj, Class c){
             if(c.isInstance(obj)) return true;
             if(obj instanceof AntiProxy && c.isInstance(((AntiProxy)obj).self()) return true;
             return false;
   }
   public static boolean isAntiProxyMethod(Method method) { return method.getDeclaringClass().equals(AntiProxy.class); }
}3. newInstance    List<Class> ints = new LinkedList<Class>();
    if(clazz.isInterface()) ints.add(clazz);    //clazz is the input Class object for proxy
    else e.setSuperclass(clazz);

    if(proxiedObject)                           //proxiedObject is the input object which is the target of the proxy calls. could be null
      ints.add(AntiProxy.class);

    if(!ints.isEmpty()) { Class[] cs = new Class; ints.toArray(cs); e.setInterfaces(cs); }

    ....

    return e.create();

key 发表于 5-11-2009 15:48:09

Solution 2

boolean assigned = false;
if(proxiedObject != null && clazz.isInstance(proxiedObject)){
    //check if there is a constructor with no arguments
try{
    Class c = proxiedObject.getClass(); Constructor con = c.getDeclaredConstructor();
    int modifiers = con.getModifiers();
    if(Modifier.isPrivate(modifiers)) throw new Exception();
    assigned = true;
}catch(Exception e){
    //do nothing
}

//set other interfaces or superclass accordingly
...

kaile 发表于 6-11-2009 19:22:58

java不太熟悉,帮顶

fishyoyo 发表于 6-11-2009 20:55:21

用PROXY 创建出来的是MyClass 得代理,否则就不是PROXY模式了,当然你创建出来的新对象接口和MyClass 是一样的。.net中对proxy讲的应该讲的比较清楚了,java应该类似

key 发表于 7-11-2009 08:31:45

你说得对,的确是这样。

对于java.lang.reflect.Proxy我的了解并不是太多。我现在一直在用CGLIB,这东西功能强大,很容易做出:

1. Adapter模式
2. Proxy模式

现在java.lang.reflect.Proxy以及CGLIB的interceptor编程实现的模式,更接近Adapter模式,
因为没有强制地要求最终执行操作的必须为同一个interface的东西。
当然了,采用proxy.invoke()更方便,只不过不是强制的。

从Proxy模式的实质含义上看,它提供了一个接口剖面,让我们加入自己想处理的东西,这就是这几年提的AOP概念。
这个剖面的确很强大,以前需要能想象这个剖面的强大,但没有工具支持,自己很难简单实现这东西。reflect的出现,Proxy类的出现,CGLIB库的出现,让我们很容易实现这些功能。

现在的问题就是,我们如果只想在剖面中加入东西,加完后,这个东西还是原来的那个样子,应该怎样办?(Liskov Substitution Principle)。至少我们能有办法还原到原来的样子,又或者兼容原来的object。

可能你会问,既然程序员已经明知接下来就是Proxy到某个指定的接口或父类,就应该知道生出来的新对象的就只能是这样。你这样说很对,所以,我就说这个是Proxy模式的局限性。我现在的实际情况是:

1. 程序剖面只开在某个指定的类层次(或接口层次)(这个主要是因为Annotation的实现局限)
2. Proxy出来的对象,我希望对下一级的接口使用者透明。

如果我在每个interceptor实现时都追塑至Object这个level,程序的效率必然受影响。我要考虑的就是这个问题了。


原帖由 fishyoyo 于 6-11-2009 21:55 发表 http://www.freeoz.org/bbs/images/common/back.gif
用PROXY 创建出来的是MyClass 得代理,否则就不是PROXY模式了,当然你创建出来的新对象接口和MyClass 是一样的。.net中对proxy讲的应该讲的比较清楚了,java应该类似

lol 发表于 6-12-2009 02:18:14

不太清楚搂主说的proxy 是不是proxypattern,

Proxy模式 的目的是调用实现同样接口的类,而调用者不需要考虑具体的实现,只要通过接口调用就可以。需要跨越某些边界的时候用到的, 比如数据,web service 等。那么创建的新类应该是基于MyInterface, 而不是MyClass的。
页: [1]
查看完整版本: The Limitation of Proxy Design Pattern