我有以下层次结构:Party 是一个基类,由 Person 和 Corporation 扩展。 我需要在实体生命周期的某个时刻更改实体的对象类,但我不知道执行此操作的最佳方法是什么。
我正在为金融世界建模,所以我有一个政党可以拥有公司的股份,而只有公司可以拥有股东。像这样:
class Party {
public Set getShares();
}
class Corporation extends Party {
public Set getShareholders();
public void setShareholders(Party ss);
}
class Person extends Party {
... (some method still unknown)
}
我构建了从源读取数据的对象,可能一开始我只知道一方的名称,但不知道它是个人还是公司。 但是我需要创建一个对象,所以我创建了一个通用的 Party。在那之后,可能会知道更多的信息,比如我的党是一家公司。因此,我需要将代表该实体的类从 Party 更改为 Corporation。 到目前为止,我的解决方案是构建一个新对象,将旧数据复制到其中。 但我对此并不满意,我想知道实现我想要实现的目标的最佳方式、模式或其他任何东西是什么。
我想到了State Pattern ,但我认为它最适合其他情况。
一般来说,我不希望真的改变对象的类别。我想要的是有一些机制让客户类遵守不同类型的契约。也就是说,我不希望一个类能够在一个人身上调用 setShareholders,我如何实现这一点并不重要,我的意思是也许实体是一个人这一事实可以用其他方式表示,而不是使用人类。
最佳答案
In general, I don't want really to change the class of the objects. What I want is to have some mechanism to make client classes to obey to the contracts of the different types. I.e., I don't want a class to be able to call setShareholders on a Person, and it's not important how I can achieve this, I mean that maybe the fact that an entity is a Person can be represented on other ways than using a class Person.
最后一段让我想到 dynamic proxy可以满足您的需求。如果您有一个“实体”E,“是一个人 [that] 可以用其他方式表示,而不是使用类 Person”。代理可以包装您的实体 E 并仅“实现”/呈现所需的接口(interface) Person
(同时隐藏任何其他已实现的接口(interface)或关于 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("\n *** Call a method A.methodA() on proxy 'a'");
a.methodA();
try {
System.out.println("\n *** Call a method B.methodB() on proxy 'a' (throws exception)");
((B) a).methodB();
} catch (final Exception ex) {
ex.printStackTrace(System.out);
}
System.out.println("\n *** Call a method B.methodB() on proxy 'b'");
b.methodB();
try {
System.out.println("\n *** Call a method A.methodA() on proxy 'b' (throws exception)");
((A) b).methodA();
} catch (final Exception ex) {
ex.printStackTrace(System.out);
}
System.out.println("\n *** Call a method A.methodA() on proxy 'ab'");
ab.methodA();
System.out.println("\n *** Call a method B.methodB() on proxy 'ab'");
((B) ab).methodB();
// ClassCastException: $Proxy0 cannot be cast to DynamicProxy$Foo
try {
System.out.println("\n *** 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("\n *** 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("\n *** 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("\n *** 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)
关于java - 在实体生命周期的某个时刻改变实体的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3906688/