API和实现之间的分离是否应该完全分开?

时间:2011-05-22 18:27:58

标签: java api implementation isolation

在大型软件实现中,通常建议在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代码从实现代码中完全分离或隔离是否有任何好处?或者这只是纯粹主义者试图达到完美而没有什么实际好处?

4 个答案:

答案 0 :(得分:6)

我一直都理解将界面与实现分开的要求意味着您不会将 的实现与 混合在一起。因此,在上面的示例中,混合api和实现将意味着在api中暴露特定于SeparationImpl如何实现api的东西。

作为示例,请查看如何在各种集合类中实现迭代。有更具体的方法可以检索特定集合中的元素(例如,通过ArrayList中的位置),但这些方法不会在Collection中公开,因为它们特定于具体的ArrayList的实现方式。

我还看到了具有巨大接口目录的项目,每个接口都有一个具体的实现,每个接口都在机械上重现每个方法的具体实现,这看起来像是一个完全没有意义的“假装”抽象,因为它是实际上并没有提供任何逻辑抽象。

答案 1 :(得分:4)

OSGi中经常使用的一种技术是将API与实现分开。 API应该自行编译,避免直接引用任何实现。

答案 2 :(得分:2)

彼得和史蒂夫的答案已经足够了,但我想补充更多 - 如果你只有单一的接口或抽象类的实现,那么将接口或抽象类作为它的抽象目的就没有意义。
在你的情况下,我真的不明白 - 为什么你将Separation实现为抽象类,而SeparationImpl本身可以是API类,或者如果你有不同的实现,Separation可以是一个不可理解的如果你有一些共同的功能,那么你可以有另一个实现你的接口的抽象类,然后SeparationImpl从该抽象类继承。样本类层次结构看起来像是

interface Separation --> AbstractSeparation --> SeparationImpl 

就像标准馆藏一样

interface List --> AbstractList --> ArrayList

答案 3 :(得分:2)

除了其他作者的好处之外,我还会提到单元测试目的:

当接口不是类时,模拟对象非常容易。