【问题标题】:Should separation between API and Implementation be total?API和实现之间的分离应该是完全的吗?
【发布时间】:2011-08-30 16:47:01
【问题描述】:

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

【问题讨论】:

    标签: java api implementation isolation


    【解决方案1】:

    我一直理解将接口与实现分开的要求意味着您不要将实现的如何什么混在一起。因此,在您上面的示例中,将 api 和实现混合意味着在 api 中公开特定于 SeparationImpl 如何实现您的 api 的内容。

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

    我还看到有大量接口目录的项目,每个都有一个具体的实现,并且每个都机械地复制其具体实现中的每个方法,这似乎是一个完全没有意义的“假装”抽象,因为它是实际上没有提供任何逻辑抽象。

    【讨论】:

      【解决方案2】:

      在 OSGi 中经常使用的一种技术是将 API 放在单独的模块中以实现实现。 API 应自行编译,避免直接引用任何实现。

      【讨论】:

      • 这对于 OSGi 来说是绝对必要的还是只是好的实践?
      • 使用一些框架,如 iPOJO 是必要的,但您不必在所有情况下都这样做(我不需要)
      【解决方案3】:

      Peter 和 Steve 的答案已经足够了,但我想补充更多——如果你曾经只有一个接口或抽象类的实现,那么拥有接口或抽象类是没有意义的,因为它违背了抽象的目的。
      在你的情况下,我真的不明白 - 为什么你将 Separation 实现为抽象类,而不是 SeparationImpl 本身可以是 API 类,或者如果你有不同的实现 Separation 可以是 inetrface 并且如果你有一些常见的功能然后你可以让另一个抽象类实现你的接口,然后 SeparationImpl 从那个抽象类继承。示例类层次结构看起来像

      interface Separation --> AbstractSeparation --> SeparationImpl 
      

      就像标准的集合库

      interface List --> AbstractList --> ArrayList
      

      【讨论】:

      • 即使只有一个生产实现,ABC 和接口通常仍然是一件好事;首先,它们强制执行干净的关注点分离。其次,它们允许通过模拟轻松进行单元测试。
      • 我试图说明这样一个事实:有时,您需要访问 API 的实例化,一种方法是从 API 本身提供它。我同意,这可以仅通过界面完成。
      • @Oli Charlesworth - 我们可以模拟具体的类,至少不需要有模拟目的的接口。
      • @Premraj 你如何保证模拟的 API 与实现的 API 匹配?对于接口,这是微不足道的。模拟本身就是一个简单的、精简的实现,因此通过模拟,您就有了第二个实现。
      【解决方案4】:

      除了其他作者的优点之外,我还要提到单元测试的目的:

      使用接口而不是类时,模拟对象要容易得多。

      【讨论】:

        猜你喜欢
        • 2012-01-01
        • 2019-03-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多