说我是模特梦:
public interface Dream {
void start();
}
public class SimpleDream implements Dream {
// implementation here...
}
public class Inception implements Dream {
Dream inner;
// implementation here...
}
现在假设我有一个用于这些梦的装饰类:
public class Decorator implements Dream {
Dream decorated;
public void start() {
// do something else
decorated.start();
}
}
我希望能够编写一个方法,将采取任何Dream
实例,并装饰它与Decorator
递归(字段以及)。我能够用反射来编写这样的方法,但是在尝试装饰Dream
子类型的字段时遇到了一个问题:
public class LucidDream implements Dream {
SimpleDream inner;
// implementation here...
}
我的通用方法将尝试设置一个新的Decorator
,将SimpleDream
包装到LucidDream
的inner
字段中,并且这样做(与Field.set
一起)将抛出异常(java.lang.IllegalArgumentException: Can not set final X field Y to Z
)。
我试过使用代理,但是不工作。
注:
我实际上使用的是Scala,所以(a)请原谅我的Java代码,(b)如果这只能用Scala实现,我也想知道。
不幸的是,你说你不能改变LucidDream.inner
class LucidDream implements Dream{
SimpleDream inner; // CANNOT be changed to "Dream"
}
在这种情况下,据我所知,生活变得更加复杂,唯一的解决方法是使用字节码增强库(如cglib)动态扩展SimpleDream。请参阅此处的讨论(忽略他们正在讨论抽象类的事实-重点是动态扩展类而不是接口):
创建抽象类(而不是接口)代理的java.lang.reflect.Proxy替代方案
然而,这不是微不足道的(这使维护和代码部署变得复杂),所以我只有在我真的别无选择的情况下才会求助于它,也就是说,我真的需要这种级别的泛化,而且我真的不能更改为"Dream inner"....
你是这个意思吗?
public class DreamDecorator() implements Dream {
Dream decorated;
public DreamDecorator(Dream decorated) {
this.decorated = decorated;
}
public void start() {
// do something else
decorated.start();
}
}
public class LucidDream(Dream dream) implements Dream {
Dream dream;
public LucidDream(Dream dream) {
this.dream= dream;
}
}
你可以通过下面的操作将装饰简单的梦转换为清醒梦
new LucidDream(new DreamDecorator(new SimpleDream()))
或动态使用反射,例如:
Class<?> sdClazz = Class.forName(SimpleDream.class.getName());
Constructor<?> sdCtor = sdClazz.getConstructor();
SimpleDream sd = (SimpleDream) sdCtor.newInstance();
Class<?> ddClazz = Class.forName(DreamDecorator.class.getName());
Constructor<?> ddCtor = ddClazz.getConstructor(Dream.class);
DreamDecorator dd = (DreamDecorator) ddCtor.newInstance(new Object[] { sd });
Class<?> clazz = Class.forName(LucidDream.class.getName());
Constructor<?> ctor = clazz.getConstructor(Dream.class);
LucidDream lucidDream = (LucidDream) ctor.newInstance(new Object[] { dd});