有没有一种方法可以用比这少的代码来扩展现有的接口实现?
我们假设我们有一个接口“I”和n个名为“C1”到“Cn”的“I”的实现。让我们进一步假设接口以及实现驻留在无法更改的外部库中。最后,让我们假设我们正在使用Java 8.
现在我们要扩展“I”的所有实现的功能。
如果“I”是可更改的,我们可以简单地向其添加默认实现的新方法,就像Oracle在推出流API时所做的那样。不幸的是,“我”是不可改变的。
我目前的解决方案如下:
创建一个新的接口“IX”,它扩展了“I”并包含所需的新方法作为默认实现。
因为“C1”到“Cn”没有实现“IX”而是“I”,我们需要实现“CX1”到“CXn”来使用新功能。这是我不喜欢的部分。我更喜欢一种像匿名类一样快速创建实现的方法。
这里有一些代码示例来说明我的方法:
有没有一种方法可以用比这少的代码来扩展现有的接口实现?
// Instantiate existing "C9" implementation of "I"
I object = new C9();
// Definition of interface "IX"
public interface IX extends I {
default void newMethod() {
// Do something
}
}
// Example definition of implementation "CX9"
// Off course, this needs to be done for all "C1" to "Cn".
public class CX9 extends C9 implements IX {}
// Instantiate extended implementation "C9"
IX object = new CX9();
因为“CX1”的定义为“CXN”不需要任何机构实施可言,我认为这些样板,并希望得到摆脱他们。我其实更喜欢类似以下的东西。
IX object = new (C9 implements IX)() {};
这当然不是有效的Java代码。这个想法是创建一个基于现有类(“C9”)实现额外接口(“IX”)的匿名类。有没有办法用标准的Java做到这一点?
我绝对想用标准的Java来做这件事,并且不需要字节码操作。当然,我可以使用包装器或动态代理,但“我”和“C”定义了很多方法。因此,我最终会得到更多的样板代码。
我承认这个问题纯粹是学术问题,因为最终它是关于在每个“I”实现中只删除一行代码。但我仍然对可能的解决方案感兴趣。
如果您喜欢更实用的方法,假设您希望在未知的实现集上实施类似流式API的内容,而无需更改底层接口。
感谢您对此的意见。
如果您不想“混入”接口,则具有空体的匿名类将完成这项工作。
IX object = new C9(){};
(假设C9
已经实现IX
)
现在object
是C9
一个匿名子类的实例。
但如果C9
自己尚未实现C9
,没有纯粹的Java除了解决方案修改C9
......这使得C9X
不必要的。
但是请注意,修改C9
也执行IX
应该是良性的。首先,它不会破坏二进制兼容性。
解决此类事情的标准方法是代表团。因为我们不知道你的I
也不C1
.. C9
类型的任何东西,我将使用一个俗称接口示范:
public interface ExtSet<T> extends Set<T> {
default T reduce(BinaryOperator<T> op) {
Iterator<T> it = iterator();
T t=it.next();
while(it.hasNext()) t=op.apply(t, it.next());
return t;
}
public static <T> ExtSet<T> enhance(Set<T> set) {
if(set instanceof ExtSet) return (ExtSet<T>)set;
final class Enhanced extends AbstractSet<T> implements ExtSet<T> {
public Iterator<T> iterator() { return set.iterator(); }
public int size() { return set.size(); }
public boolean contains(Object o) { return set.contains(o); }
public boolean add(T e) { return set.add(e); }
public boolean remove(Object o) { return set.remove(o); }
}
return new Enhanced();
}
}
代表团实现必须做更多的工作比可能是空的延伸类体,但它只有做一次和将所有接口实现工作,甚至不知道他们,即
ExtSet<String> set1=ExtSet.enhance(new TreeSet<>());
Collections.addAll(set1, "foo", "bar", "baz");
System.out.println(set1.reduce(String::concat));
ExtSet<Integer> set2=ExtSet.enhance(new HashSet<>());
Collections.addAll(set2, 100, 42, 7);
System.out.println(set2.reduce(Integer::sum));
ExtSet<Thread.State> set3=ExtSet.enhance(
EnumSet.of(Thread.State.TERMINATED, Thread.State.NEW));
System.out.println(set3.reduce(BinaryOperator.minBy(Comparator.naturalOrder())));
这类似于如何checkedSet
,synchronizedSet
和unmodifiableSet
增强(或限制)现有的Set
实现。
所以你说所有你现有的Cn类只有一个默认的构造函数?那么所有这些都可以轻松地进行分类? – GhostCat
@PavneetSingh不!没有! Code Review认为这些问题是假设的,这是[off-topic](http://codereview.stackexchange.com/help/on-topic)。 – Mast
@PhilippSander看到上面的评论。我敢肯定,如果有人开始迁移,迁移将被拒绝。 Code Review不会接受它。 – Mast