首页 > 解决方案 > 在接口中创建具体实现的新实例 - 这是反模式吗?

问题描述

假设我有两个不同实现类的接口,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()方法。

编辑

此外,在他看来,如果我们决定更改MyAuthorDaoImpl1MyAuthorDaoImpl2. 因为唯一的变化是getInstance()方法。

标签: javainterfacedaodesign-principles

解决方案


这个实现是一个循环依赖,大致如下:

循环依赖

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

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

class AuthorDaoFactory {

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

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

在此处输入图像描述

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

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

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

那么具体的实现方式是什么?你不知道也不在乎,你只知道它是 type Calendar


推荐阅读