【问题标题】:Creating new instance of concrete implementation in interface - is this an antipattern?在接口中创建具体实现的新实例 - 这是反模式吗?
【发布时间】:2021-06-08 12:10:01
【问题描述】:

假设我的接口AuthorDao 具有两个不同的实现类,例如MyAuthorDaoImpl1MyAuthorDaoImpl2

在我的界面 AuthorDao 中,我有一些基本的 crud 方法和 一个额外的方法,即 static,用于获取 MyAuthorDaoImpl1 的新实例。

看起来像这样:

public interface AuthorDao {

    void methodA();
    void methodB();
    ...
   
    static MyAuthorDaoImpl getInstance() {
        return new MyAuthorDaoImpl1();
    }
}

问题

  1. 这个静态方法getInstance()不是反模式吗? 因为在我看来,我们不应该将我们的界面依赖于具体的 实现类,但我的朋友说没关系,他很确定,这应该是这样的。他说这是工厂方法
  2. 他说我们可以通过构造函数创建这个接口的实例,我们不必使用这个static方法,所以这没什么不好。真的吗,这没什么不好?我认为这是紧耦合的例子,接口不应该依赖于具体的实现,但他说事实并非如此。
  3. 他指的是这和Calendar类中的情况一样,因为还有getInstance()方法。

编辑

另外,在他看来,如果我们决定将MyAuthorDaoImpl1 更改为MyAuthorDaoImpl2,这种静态方法将简化重构。 因为唯一的变化将在getInstance() 方法中。

【问题讨论】:

  • 不,这不是工厂模式。很好,你对此提出质疑。接口的目的是成为契约。合约可以有静态方法,但我认为它们不应该生成接口实现的实例......
  • Calender类是一个抽象类。抽象类可以具有生成 x(接口)实现的方法。您正走在成为优秀开发人员的正确道路上。
  • @SusanMustafa 我认为你提到这是你的意见很好。没有什么是明确的。 List.ofSet.of 等是添加到提到的Calendar 实例的好例子。再补充一点,我认为只要生成的 API 不会使合约的客户端依赖于特定的实现,就可以了。 (我猜如果静态接口方法来得正是时候,Collections 类就不会存在)。 getInstance() 方法唯一的代码异味是它不需要输入,这意味着存在“第 1 个”实现。

标签: java interface dao design-principles


【解决方案1】:

这个实现是circular dependency,大致如下:

虽然它很可能在 Java 中工作,但想象一下,如果您后来决定实现 ABetterAuthorDaoImpl 时不再包含类 MyAuthorDaoImpl 会发生什么。现在您必须更改界面。在这种情况下,这是一个微小的变化,但可以在更大的范围内想象它。

通常工厂方法返回接口类型而不是实现类型。示例:

class AuthorDaoFactory {

    static AuthorDao getInstance() {
        return new MyAuthorDaoImpl1();
    }
}

这避免了循环依赖,如下图所示:

您会注意到依赖项中没有循环路径。对于这个简单的示例,这可能无关紧要,但是如果您的工厂方法创建了一个基于配置动态加载的类的实例呢?这是Inversion of Control (IoC) 的常见示例,通常用于为不同硬件提供通用接口。实现隐藏在接口后面。

您会注意到Java Calendar 类方法getInstance 返回类型Calendar。底层实现可能是特定于语言环境的。如果您查看 Java 文档中对该方法的描述,它会说:

使用默认时区和语言环境获取日历。返回的日历基于具有默认语言环境的默认时区中的当前时间。

那么实现是什么?你不知道也不在乎,你只知道它是Calendar类型的。

【讨论】:

    猜你喜欢
    • 2018-04-25
    • 1970-01-01
    • 2017-04-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-30
    • 2011-10-30
    相关资源
    最近更新 更多