一般来说,我并不想真正更改对象的类。我想要的是有一些机制使客户端类遵守不同类型的契约。也就是说,我不希望一个类能够在Person上调用setShareholders,我如何实现这一点并不重要,我的意思是,也许一个实体是Person这一事实可以用其他方式表示,而不是使用类Person。
最后一段让我想到了动态代理可以满足您的需求。如果您有一个”实体“E,则“是一个Person[可以]以其他方式表示,而不是使用类Person”。代理可以包装您的实体E并“实现”/仅呈现所需的接口Person
(同时隐藏任何其他已实现的接口或有关E的实现详细信息)。
编辑:由于OP发现答案很有用,我添加了一个实用程序类和演示代码:
某些代码:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* Utilities to support using dynamic proxies
*/
public class DynamicProxy {
/**
* An invocation handler that passes calls to its delegate. This class
* could be subclassed to provide dynamic method invocation handling
* while still being able to fall back to the delegate object s methods.
*
* @see InvocationHandler
*/
public static class DelegatingInvocationHandler
implements InvocationHandler {
/** The object this proxy is wrapping */
private final Object delegate;
/**
* Creates a delegate invocation handler around an object
*
* @param object
* The object to wrap
*/
public DelegatingInvocationHandler(final Object delegate) {
this.delegate = delegate;
}
/* (non-Javadoc)
*
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object,
* java.lang.reflect.Method, java.lang.Object[])
*/
@Override
public Object invoke(final Object proxy, final Method m,
final Object[] args) throws Throwable {
Object result;
try {
result = m.invoke(delegate, args);
} catch (final InvocationTargetException e) {
throw e.getTargetException();
} catch (final Exception e) {
throw new RuntimeException("unexpected invocation exception: "
+ e.getMessage());
}
return result;
}
}
/**
* Create a dynamic proxy that implements only a specified subset of the
* original object s implemented interfaces. The proxy allows you to
* essentially hide the other interfaces implemented by the original
* object.
*
* @param delegate
* the object that the proxy "proxies" for (a.k.a. the delegate
* that handles the calls the proxy "allows" through)
* @param requiredInterface
* one of the interfaces of the delegate that the proxy exposes
* @param moreInterfaces
* any additional interfaces of the delegate to expose
* @return the proxy
* a proxy for the delegate that can be cast to any of the
* specified interfaces
*/
public static <T> T createSelectiveProxy(final T delegate,
final Class<T> requiredInterface,
final Class<?>... moreInterfaces) {
if (delegate == null) {
throw new IllegalArgumentException(
"The delegate object cannot be null");
}
return createProxy(new DelegatingInvocationHandler(delegate),
requiredInterface, moreInterfaces);
}
/**
* Creates a proxy using the specified invocation handler.
*
* @param object
* the implementing object that proxy wraps
* @param invocationHandler
* the interfaces
* @param moreInterfaces
* the interfaces
* @return the object
*/
@SuppressWarnings("unchecked")
public static <T> T createProxy(final InvocationHandler invocationHandler,
final Class<T> requiredInterface,
final Class<?>... moreInterfaces) {
if (invocationHandler == null) {
throw new IllegalArgumentException(
"The invocation handler cannot be null");
}
final int size = (moreInterfaces != null ? moreInterfaces.length : 0);
final Class<?>[] interfaces = new Class<?>[size + 1];
interfaces[0] = requiredInterface;
System.arraycopy(moreInterfaces, 0, interfaces, 1, moreInterfaces.length);
return (T) Proxy.newProxyInstance(invocationHandler.getClass()
.getClassLoader(), interfaces, invocationHandler);
}
}
演示:
public class DynamicProxyDemo {
private interface A {
void methodA();
}
private interface B {
void methodB();
}
private static class Foo implements A, B {
public void methodA() {
System.out.println("A");
}
public void methodB() {
System.out.println("B");
}
}
private DynamicProxyDemo() {}
public static void main(final String[] args) {
final Foo foo = new Foo(); // implements both interfaces
// calls foo s methods, but only A methods
final A a = DynamicProxy.createSelectiveProxy(foo, A.class);
// calls foo s methods, but only B methods
final B b = DynamicProxy.createSelectiveProxy(foo, B.class);
// calls foo s methods, but A and B methods
final A ab = DynamicProxy.createSelectiveProxy(foo, A.class, B.class);
System.out.println("
*** Call a method A.methodA() on proxy a ");
a.methodA();
try {
System.out.println("
*** Call a method B.methodB() on proxy a (throws exception)");
((B) a).methodB();
} catch (final Exception ex) {
ex.printStackTrace(System.out);
}
System.out.println("
*** Call a method B.methodB() on proxy b ");
b.methodB();
try {
System.out.println("
*** Call a method A.methodA() on proxy b (throws exception)");
((A) b).methodA();
} catch (final Exception ex) {
ex.printStackTrace(System.out);
}
System.out.println("
*** Call a method A.methodA() on proxy ab ");
ab.methodA();
System.out.println("
*** Call a method B.methodB() on proxy ab ");
((B) ab).methodB();
// ClassCastException: $Proxy0 cannot be cast to DynamicProxy$Foo
try {
System.out.println("
*** Call a method A of class Foo on proxy a (throws exception)");
((Foo) a).methodA();
} catch (final Exception ex) {
ex.printStackTrace(System.out);
}
// ClassCastException: $Proxy1 cannot be cast to DynamicProxy$Foo
try {
System.out.println("
*** Call a method B of class Foo on proxy b (throws exception)");
((Foo) b).methodB();
} catch (final Exception ex) {
ex.printStackTrace(System.out);
}
// ClassCastException: $Proxy0 cannot be cast to DynamicProxy$B
try {
System.out.println("
*** Call a method B.methodB() on proxy a (throws exception)");
((B) a).methodB();
} catch (final Exception ex) {
ex.printStackTrace(System.out);
}
// ClassCastException: $DynamicProxy1 cannot be cast to DynamicProxy$A
try {
System.out.println("
*** Call a method A.methodA() on proxy b (throws exception)");
((A) b).methodA();
} catch (final Exception ex) {
ex.printStackTrace(System.out);
}
}
}
运行时间:
*** Call a method A.methodA() on proxy a
A
*** Call a method B.methodB() on proxy a (throws exception)
java.lang.ClassCastException: net.bertfernandez.reflection.$Proxy0 cannot be cast to net.bertfernandez.reflection.DynamicProxyDemo$B
at net.bertfernandez.reflection.DynamicProxyDemo.main(DynamicProxyDemo.java:49)
*** Call a method B.methodB() on proxy b
B
*** Call a method A.methodA() on proxy b (throws exception)
java.lang.ClassCastException: net.bertfernandez.reflection.$Proxy1 cannot be cast to net.bertfernandez.reflection.DynamicProxyDemo$A
at net.bertfernandez.reflection.DynamicProxyDemo.main(DynamicProxyDemo.java:59)
*** Call a method A.methodA() on proxy ab
A
*** Call a method B.methodB() on proxy ab
B
*** Call a method A of class Foo on proxy a (throws exception)
java.lang.ClassCastException: net.bertfernandez.reflection.$Proxy0 cannot be cast to net.bertfernandez.reflection.DynamicProxyDemo$Foo
at net.bertfernandez.reflection.DynamicProxyDemo.main(DynamicProxyDemo.java:73)
*** Call a method B of class Foo on proxy b (throws exception)
java.lang.ClassCastException: net.bertfernandez.reflection.$Proxy1 cannot be cast to net.bertfernandez.reflection.DynamicProxyDemo$Foo
at net.bertfernandez.reflection.DynamicProxyDemo.main(DynamicProxyDemo.java:81)
*** Call a method B.methodB() on proxy a (throws exception)
java.lang.ClassCastException: net.bertfernandez.reflection.$Proxy0 cannot be cast to net.bertfernandez.reflection.DynamicProxyDemo$B
at net.bertfernandez.reflection.DynamicProxyDemo.main(DynamicProxyDemo.java:89)
*** Call a method A.methodA() on proxy b (throws exception)
java.lang.ClassCastException: net.bertfernandez.reflection.$Proxy1 cannot be cast to net.bertfernandez.reflection.DynamicProxyDemo$A
at net.bertfernandez.reflection.DynamicProxyDemo.main(DynamicProxyDemo.java:97)