在接口中创建具体实现的新实例——这是反模式吗?
Creating new instance of concrete implementation in interface - is this an antipattern?
假设我的接口 AuthorDao
有两个不同的实现 class,例如 MyAuthorDaoImpl1
和 MyAuthorDaoImpl2
。
在我的界面中 AuthorDao
我有一些基本的 crud 方法和 一个额外的方法 static
用于获取 [=12= 的新实例].
看起来像这样:
public interface AuthorDao {
void methodA();
void methodB();
...
static MyAuthorDaoImpl getInstance() {
return new MyAuthorDaoImpl1();
}
}
问题
- 这个静态方法
getInstance()
是不是反模式?
因为在我看来我们不应该依赖具体的界面
实现 class,但我的朋友说没关系,他很确定,这应该像这样工作。他说是工厂方法.
- 他说我们可以通过构造函数创建这个接口的实例,我们不必使用这个
static
方法,所以这没什么不好的。真的,这没什么不好吗?我认为这是紧耦合的例子,接口不应该依赖于具体实现,但他说情况并非如此。
- 他说这跟
Calendar
class是一样的,因为还有getInstance()
方法
编辑
此外,在他看来,如果我们决定将 MyAuthorDaoImpl1
更改为 MyAuthorDaoImpl2
,则此静态方法将简化重构。
因为唯一的变化是 getInstance()
方法。
这个实现是一个circular dependency,大致是这样的:
虽然它可能会在 Java 中工作,但想象一下如果您不再包含 class MyAuthorDaoImpl
之后您决定实施 ABetterAuthorDaoImpl
会发生什么。现在你必须改变界面。在这种情况下这是一个很小的变化,但想象一下更大的规模。
通常是工厂方法 returns 接口类型而不是实现类型。示例:
class AuthorDaoFactory {
static AuthorDao getInstance() {
return new MyAuthorDaoImpl1();
}
}
这避免了循环依赖,如下图所示:
您会注意到依赖项中没有循环路径。对于这个简单的示例,这可能无关紧要,但是如果您的工厂方法创建了一个 class 的实例,该实例是基于配置动态加载的呢?这是 Inversion of Control (IoC) 的一个常见示例,通常用于为不同硬件提供通用接口等操作。实现隐藏在界面后面。
您会注意到 Java Calendar
class 方法 getInstance
returns 类型 Calendar
。底层实现可能是特定于语言环境的。如果您查看 Java 文档中的方法描述,它会说:
Gets a calendar using the default time zone and locale. The Calendar returned is based on the current time in the default time zone with the default locale.
那具体是怎么实现的呢?你不知道也不关心,你只知道是Calendar
.
类型
假设我的接口 AuthorDao
有两个不同的实现 class,例如 MyAuthorDaoImpl1
和 MyAuthorDaoImpl2
。
在我的界面中 AuthorDao
我有一些基本的 crud 方法和 一个额外的方法 static
用于获取 [=12= 的新实例].
看起来像这样:
public interface AuthorDao {
void methodA();
void methodB();
...
static MyAuthorDaoImpl getInstance() {
return new MyAuthorDaoImpl1();
}
}
问题
- 这个静态方法
getInstance()
是不是反模式? 因为在我看来我们不应该依赖具体的界面 实现 class,但我的朋友说没关系,他很确定,这应该像这样工作。他说是工厂方法. - 他说我们可以通过构造函数创建这个接口的实例,我们不必使用这个
static
方法,所以这没什么不好的。真的,这没什么不好吗?我认为这是紧耦合的例子,接口不应该依赖于具体实现,但他说情况并非如此。 - 他说这跟
Calendar
class是一样的,因为还有getInstance()
方法
编辑
此外,在他看来,如果我们决定将 MyAuthorDaoImpl1
更改为 MyAuthorDaoImpl2
,则此静态方法将简化重构。
因为唯一的变化是 getInstance()
方法。
这个实现是一个circular dependency,大致是这样的:
虽然它可能会在 Java 中工作,但想象一下如果您不再包含 class MyAuthorDaoImpl
之后您决定实施 ABetterAuthorDaoImpl
会发生什么。现在你必须改变界面。在这种情况下这是一个很小的变化,但想象一下更大的规模。
通常是工厂方法 returns 接口类型而不是实现类型。示例:
class AuthorDaoFactory {
static AuthorDao getInstance() {
return new MyAuthorDaoImpl1();
}
}
这避免了循环依赖,如下图所示:
您会注意到依赖项中没有循环路径。对于这个简单的示例,这可能无关紧要,但是如果您的工厂方法创建了一个 class 的实例,该实例是基于配置动态加载的呢?这是 Inversion of Control (IoC) 的一个常见示例,通常用于为不同硬件提供通用接口等操作。实现隐藏在界面后面。
您会注意到 Java Calendar
class 方法 getInstance
returns 类型 Calendar
。底层实现可能是特定于语言环境的。如果您查看 Java 文档中的方法描述,它会说:
Gets a calendar using the default time zone and locale. The Calendar returned is based on the current time in the default time zone with the default locale.
那具体是怎么实现的呢?你不知道也不关心,你只知道是Calendar
.