不依赖于实现的工厂

Factory which is not dependant on implementation

我有一个 api,它有一些基本实现。我有一个工厂,它向客户提供 api 的实例。

我想更改我的工厂以使其更通用,因此,如果将生成 api 的新实现并将其 jar 文件放入类路径中,工厂将理解它以及任何更改不需要。

如果您想从理论开始。请阅读 Dependency inversion principle

In object-oriented programming, the dependency inversion principle refers to a specific form of decoupling software modules. When following this principle, the conventional dependency relationships established from high-level, policy-setting modules to low-level, dependency modules are inverted (i.e. reversed), thus rendering high-level modules independent of the low-level module implementation details.

A. High-level modules should not depend on low-level modules. Both should depend on abstractions.

B. Abstractions should not depend on details. Details should depend on abstractions.

The principle inverts the way some people may think about object-oriented design, dictating that both high- and low-level objects must depend on the same abstraction.

依赖注入库

至于具体实现,你在Java中有很多。专门针对Dependency Injection approach. Spring Framework obviously comes to mind. But you can also look at Java EE Context and Dependency Injection.

接口注入

您还可以...

  1. 手动加载 Jars:How should I load Jars dynamically at runtime?
  2. 使用接口注入Spring interface injection example(这个标题说Spring,但答案显示接口注入不需要Spring)

使用 java SPI,服务提供商接口。

  • API jar - 提供单一接口。
  • Provider jar - 在 jars 中提供实现。您甚至可以将多个实现放在一个 jar 中。在文本文件 META-INF/services/my.package.MyInterface 中列出了实现 class(es).
  • Application - 在应用程序中,编译不需要实现 jar: 在 Maven 作用域运行时。

服务发现发生在 ServiceLoader<T>:

public static void main(String[] args) {
    ServiceLoader<MyInterface> loader = ServiceLoader.load(MyInterface.class);
    for (MyInterface api : loader) {
        api. ...
    }
    // Or take the first implementation:
    MyInterface api = loader.iterator().next();
}

您可以在 API jar 中提供一个 class,其中包含用于该发现机制的静态函数。

优点:

  • 分离
  • 可能的几种实现方式
  • 实现的选择可以动态完成

罐子示例

  • xxx-api.jar
    • my/package/MyInterface.class
  • xxx-第一-impl.jar
    • META-INF/services/my.package.MyInterface
      • my.package.impl.MyImpl1
    • my/package/impl/MyImpl1.class
      • public class MyImpl1 implements MyInterface { ... }
  • myapp1.jar