这个问题已经有6个月的历史了,@CoronA的精彩答案已经满足并被@walkeros接受,但我想我会在这里添加一些东西,因为我认为这可以推一个额外的步骤。
正如@CoronA在他的答案的评论中所讨论的那样,动态代理解决方案不必在(即)中创建和维护一长串方法,而是将其移动到接口。问题是,您仍然必须为接口中的方法创建和维护一长串签名,这可能更简单一些,但不能完全解决问题。如果您无权访问以了解所有方法,则尤其如此。MyClass
WrapperClass
public void methodN() { delegate.methodN(); }
MyClass
MyClass
根据装饰代码的三种方法,
对于较长的类,程序员必须选择两种邪恶中的较小者:实现许多包装器方法并保留装饰对象的类型,或者维护简单的装饰器实现并牺牲保留装饰对象类型。
因此,也许这是装饰器模式的预期限制。
然而,@Mark-Bramnik在插入Java类方法(没有接口)时使用CGLIB给出了一个引人入胜的解决方案。我能够将其与@CoronaA的解决方案相结合,以创建一个可以覆盖各个方法的包装器,但随后将其他所有内容传递给包装的对象,而无需接口。
这是 .MyClass
public class MyClass {
public void method1() { System.out.println("This is method 1 - " + this); }
public void method2() { System.out.println("This is method 2 - " + this); }
public void method3() { System.out.println("This is method 3 - " + this); }
public void methodN() { System.out.println("This is method N - " + this); }
}
这是仅覆盖 .正如您将在下面看到的,未重写的方法实际上没有传递给委托,这可能是一个问题。WrapperClass
method2()
public class WrapperClass extends MyClass {
private MyClass delagate;
public WrapperClass(MyClass delegate) { this.delagate = delegate; }
@Override
public void method2() {
System.out.println("This is overridden method 2 - " + delagate);
}
}
这是扩展.它使用@Mark-Bramnik所描述的使用CGLIMB的代理解决方案。它还采用@CononA的方法来确定是将方法发送到包装器(如果它被覆盖)还是将包装对象(如果不是)。MyInterceptor
MyClass
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class MyInterceptor extends MyClass implements MethodInterceptor {
private Object realObj;
public MyInterceptor(Object obj) { this.realObj = obj; }
@Override
public void method2() {
System.out.println("This is overridden method 2 - " + realObj);
}
@Override
public Object intercept(Object arg0, Method method, Object[] objects,
MethodProxy methodProxy) throws Throwable {
Method m = findMethod(this.getClass(), method);
if (m != null) { return m.invoke(this, objects); }
Object res = method.invoke(realObj, objects);
return res;
}
private Method findMethod(Class<?> clazz, Method method) throws Throwable {
try {
return clazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
} catch (NoSuchMethodException e) {
return null;
}
}
}
这是运行它时获得的结果。Main
import net.sf.cglib.proxy.Enhancer;
public class Main {
private static MyClass unwrapped;
private static WrapperClass wrapped;
private static MyClass proxified;
public static void main(String[] args) {
unwrapped = new MyClass();
System.out.println(">>> Methods from the unwrapped object:");
unwrapped.method1();
unwrapped.method2();
unwrapped.method3();
wrapped = new WrapperClass(unwrapped);
System.out.println(">>> Methods from the wrapped object:");
wrapped.method1();
wrapped.method2();
wrapped.method3();
proxified = createProxy(unwrapped);
System.out.println(">>> Methods from the proxy object:");
proxified.method1();
proxified.method2();
proxified.method3();
}
@SuppressWarnings("unchecked")
public static <T> T createProxy(T obj) {
Enhancer e = new Enhancer();
e.setSuperclass(obj.getClass());
e.setCallback(new MyInterceptor(obj));
T proxifiedObj = (T) e.create();
return proxifiedObj;
}
}
>>> Methods from the unwrapped object:
This is method 1 - MyClass@e26db62
This is method 2 - MyClass@e26db62
This is method 3 - MyClass@e26db62
>>> Methods from the wrapped object:
This is method 1 - WrapperClass@7b7035c6
This is overridden method 2 - MyClass@e26db62
This is method 3 - WrapperClass@7b7035c6
>>> Methods from the proxy object:
This is method 1 - MyClass@e26db62
This is overridden method 2 - MyClass@e26db62
This is method 3 - MyClass@e26db62
如您所见,当您运行 方法时,您将获得未重写的方法的包装器(即 和 )。但是,当您在 上运行方法时,所有方法都在包装的对象上运行,而不必将它们全部委托或将所有方法签名放在接口中。感谢@CoronA和@Mark-Bramnik,这似乎是一个非常酷的解决方案。wrapped
method1()
method3()
proxified
WrapperClass