在接口中创建具体实现的新实例 - 这是反模式吗?

问题描述

假设我的接口 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() 方法中。

解决方法

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

circular dependency

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

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

class AuthorDaoFactory {

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

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

enter image description here

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

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

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

那么实现是什么?您不知道也不关心,您只知道它属于 Calendar 类型。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...