如何动态递归地修饰Java/Scala中的类



说我是模特梦:

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包装到LucidDreaminner字段中,并且这样做(与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});

相关内容

  • 没有找到相关文章

最新更新