在大型软件实现中,通常建议在API设计与其实现之间进行分离.但在某些地方,它们必须重新连接(即,必须将实现重新连接到API).
以下示例显示了API设计以及通过INSTANCE对象调用其实现:
import java.util.List; public abstract class Separation { public static final Separation INSTANCE = new SeparationImpl(); // Defining a special list public static interface MySpecialList<T> extends List<T> { void specialAdd(T item); } // Creation of a special list public abstract <T> MySpecialList<T> newSpecialList(Class<T> c); // Merging of a special list public abstract <T> MySpecialList<? extends T> specialMerge( MySpecialList<? super T> a,MySpecialList<? super T> b); // Implementation of separation public static class SeparationImpl extends Separation { @Override public <T> MySpecialList<T> newSpecialList(Class<T> c) { return ...; } @Override public <T> MySpecialList<? extends T> specialMerge( MySpecialList<? super T> a,MySpecialList<? super T> b) { return ...; } } }
有人会争辩说API不应该引用实现代码.即使我们通过单独的文件将API代码与实现分开,也经常需要在API中导入实现代码(至少是类名).
解决方法
我一直都理解将接口与实现分开的要求意味着你不要将实现方式与实现方式混为一谈.因此,在上面的示例中,混合api和实现将意味着在api中暴露特定于SeparationImpl如何实现api的东西.
作为示例,请查看如何在各种集合类中实现迭代.您可以使用更具体的方法检索特定集合中的元素(例如,通过ArrayList中的位置),但这些方法不会在Collection中公开,因为它们特定于具体ArrayList的实现方式.
我还看到了具有巨大接口目录的项目,每个接口都有一个具体的实现,并且每个接口都在机械上重现每个方法的具体实现,这似乎是一个完全没有意义的“假装”抽象,因为它实际上并没有提供任何逻辑抽象.