Java 面向对象编程:动态添加功能
我正在寻找一种替代装饰图案的方法,使其更具活力。作为一个简单的例子,假设我们有以下代码:Java 面向对象编程:动态添加功能,java,oop,Java,Oop,我正在寻找一种替代装饰图案的方法,使其更具活力。作为一个简单的例子,假设我们有以下代码: interface Resource { public String getName(); } interface Wrapper extends Resource { public Resource getSource(); } interface Readable extends Resource { public InputStream getInputStream();
interface Resource {
public String getName();
}
interface Wrapper extends Resource {
public Resource getSource();
}
interface Readable extends Resource {
public InputStream getInputStream();
}
interface Listable extends Resource {
public List<Resource> getChildren();
}
class File implements Readable {
...
}
class Zip implements Listable, Wrapper {
public Zip(Readable source) { ... }
}
我不希望(也不能)堆叠所有接口以相互扩展(例如,Listable extends Readable),也不能构造所有对象来实现所有功能,因为并非所有功能都相互关联,您希望能够通过包装来动态“装饰”对象
我相信这是一个常见的问题,但有没有一种模式可以解决它?当然,使用“包装器”接口,如果您愿意,您可以探测资源链以检查功能,但我不确定这是否是一种明智的方法
更新
问题是如上所述,并非所有的功能都是相关的,因此您无法构建一个良好的接口层次结构。例如,假设您具有以下任意新功能:
interface Rateable extends Resource {
public int getRating();
}
class DatabaseRateable implements Rateable, Wrapper {
public DatabaseRateable(Resource resource) { ... }
}
如果您运行:
Resource resource = new DatabaseRateable(new Zip(new File));
结果资源“丢失”了添加的所有功能(可读、可列出等)。
如果让应课差饷租值延长,说是应课差饷租值,那将是荒谬的
我可以再次递归地检查resource.getSource()并找出所有特性。在即时回复中,没有明确的解决方案,因此递归检查可能毕竟是一个不错的选择?在我看来,这似乎是您在这里努力追求的概念,而java本身并没有这样做(请参阅我关于基于反射的java库的评论)。但是,在JVM上运行的其他语言肯定会这样做。例如-:
您可以在groovy中编写代码,使其与java代码的其余部分无缝配合,并在groovy中解决此问题。在装饰对象时,通常只装饰对象的一个接口,以修改或添加其行为的一个方面。 可以使用不同的装饰器装饰对象的另一个接口。这些装饰师可以同时存在 您可以将一个装饰器传递给一个方法,将另一个传递给另一个方法 当您希望先用几个装饰器装饰对象,然后通过代码传递对象时,这会变得很麻烦 因此,对于您的情况,我建议您再次将decorators包装到一个对象中,该对象知道资源中存在哪种decorator
class Resource {
private Readable readable;
private Listable listable;
private Rateable rateable;
setReadable(Readable readable) {
this.readable = readable;
}
setListable(Listable listable) {
this.listable = listable;
}
setRateable(Rateable rateable) {
this.rateable = rateable;
}
public boolean isRateable(){
return rateable != null;
}
public Rateable getRateable(){
return rateable;
}
// etc
}
File file1 = new File();
Resource resource = new Resource(file1);
resource.setReadable(new ReadableFile(file1));
resource.setListable(new ListableFile(file1));
resource.setRateable(new DatabaseRateableFile(file1));
然后,您可以传递资源,其用户可以发现此特定资源具有哪些功能
允许您使用注释以更干净的方式执行此操作(以及更多操作)。你把碎片组合成复合材料。不过,这确实需要一些时间来适应。为资源滚动您自己的特定实现的优点是,它更容易向其他人解释。我认为您正在寻找的是 链接的wikipedia页面有一个很好的支持它们的OOP语言列表。或者您是专门与Java联系在一起的?也许
Readable r = zip.adapt( Readable.class );
这要求方法adapt()
返回实现Readable
接口的zip
实例
这些实现通常使用一个“适配器管理器”,它知道如何为所有注册的类型构建包装器。这里可能不太合适,但是动态功能发现:
public class Features {
public <T> lookup(Class<T> intface)
throws UnsupportedOperationException {
return lookup(intface, intface.getSimpleName());
}
public <T> lookup(Class<T> intface, String name)
throws UnsupportedOperationException {
return map.get(...);
}
}
public class X {
public final Features FEATURES = new Features();
...
}
X x;
Readable r = x.FEATURES.lookup(Readable.class);
公共类功能{
公共查找(类接口)
抛出不支持的操作异常{
返回查找(intface,intface.getSimpleName());
}
公共查找(类接口、字符串名称)
抛出不支持的操作异常{
返回地图。获取(…);
}
}
公共X类{
公共最终功能=新功能();
...
}
X;
可读r=x.FEATURES.lookup(Readable.class);
我将提供我自己的建议(如原始问题中所述)作为答案。如果有足够多的人认为这是一个有价值的解决方案,或者没有更好的解决方案,我会接受它
简言之,我自己的解决方案包括使用包装器接口向后遍历资源,找出存在哪些特性。举个例子:
Resource resource = new DatabaseRateable(new Zip(new File));
你可以想象这样做:
public Readable asReadable(Resource resource) {
if (resource instanceof Readable)
return (Readable) resource;
else if (resource instanceof Wrapper)
return (asReadable( ((Wrapper) resource).getSource() );
else
return null;
}
您装饰这些对象的目的是什么?为什么
Zip
不能同时实现可读性
?您能提供一个具体的例子说明这是一个问题吗?@Dai示例在update@flup向不知道这些特性是否存在的对象动态添加特性。运行时混合(与编译时相反)可以提供一个解决方案,但是我非常依赖java。java有一个mixin实现,请参阅。它从碎片构造复合物。不过,就您的目的而言,它可能是一个有点重的解决方案。@flup如果我正确理解了框架,那么Qi4j就不是“动态”的,因为必须编译组合等。但是,这些功能完全是动态的,不需要重新构建即可正常工作。@user1109519确实如此!(假设我对你的理解正确)请看。“对象的组成可能会随着时间的推移而改变。”问题是初始对象没有实现这些特性。这些特性被添加(它们本身也可以被装饰)。decorator模式假定您只是覆盖现有方法,而不是动态添加它们。如果不完全是这样,您也可以使用decorator添加行为。是的,但是如果您添加行为,则生成的decorator仍将实现现有行为的所有方法,此时它将变得不可行。问题确实是我想要传递一个装饰对象,你不需要实现装饰器中的所有其他方法。生成的对象将具有什么类型?你会经常用同样的方式装饰对象吗?如果你想使用装饰过的对象访问上述方法,你会这样做。生成的对象主要是一种资源,在需要时会对其进行特定功能的探测。在所有可能的组合中都有无数的特性
Resource resource = new DatabaseRateable(new Zip(new File));
public Readable asReadable(Resource resource) {
if (resource instanceof Readable)
return (Readable) resource;
else if (resource instanceof Wrapper)
return (asReadable( ((Wrapper) resource).getSource() );
else
return null;
}