Java 不依赖于实施的工厂

Java 不依赖于实施的工厂,java,factory,Java,Factory,我有一个api,它有一些基本实现。我有一个工厂,它向客户提供该api的实例 我想更改我的工厂,使其更通用,因此,如果将生成api的新实现并将其jar文件放入类路径中,工厂将理解它,并且不需要进行任何更改。如果您想从理论开始。请阅读 在面向对象编程中,依赖倒置原则是指解耦软件模块的一种特定形式。当遵循这一原则时,从高级策略设置模块到低级依赖模块建立的传统依赖关系被反转(即反转),从而使高级模块独立于低级模块实现细节 A.高级模块不应依赖于低级模块。两者都应该依赖于抽象 抽象不应该依赖于细节。细节应

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


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

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

在面向对象编程中,依赖倒置原则是指解耦软件模块的一种特定形式。当遵循这一原则时,从高级策略设置模块到低级依赖模块建立的传统依赖关系被反转(即反转),从而使高级模块独立于低级模块实现细节

A.高级模块不应依赖于低级模块。两者都应该依赖于抽象

抽象不应该依赖于细节。细节应该取决于抽象

该原则颠覆了一些人对面向对象设计的想法,规定高层和底层对象必须依赖于同一个抽象

依赖项注入库

至于具体的实现,Java中有很多。特别是针对这种方法。显然,我想到了。但您也可以看看JavaEE

接口注入

你也可以

  • 手动加载罐子:
  • 使用接口注入:(这个标题说的是Spring,但答案显示接口注入不需要Spring)

  • 使用JavaSPI,服务提供者接口

    • API jar-提供一个单一接口
    • 提供程序jar-在jar中提供实现。您甚至可以将几个实现放在一个jar中。在一个文本文件
      META-INF/services/my.package.MyInterface
      中,列出了实现类
    • 应用程序-在应用程序中,编译不需要实现jar: 在maven作用域运行时中
    服务发现是通过
    服务加载器进行的

    publicstaticvoidmain(字符串[]args){
    ServiceLoader=ServiceLoader.load(MyInterface.class);
    for(MyInterface api:loader){
    api。。。
    }
    //或者以第一次实施为例:
    MyInterface api=loader.iterator().next();
    }
    
    您可以在API jar中为该发现机制提供一个带有静态函数的类

    优点:

    • 分离
    • 几种可能的实现
    • 可以动态地选择实现

    罐子示例

    • xxx-api.jar
      • my/package/MyInterface.class
    • xxx-first-impl.jar
      • META-INF/services/my.package.MyInterface
        • my.package.impl.MyImpl1
      • my/package/impl/MyImpl1.class
        • 公共类MyImpl1实现MyInterface{…}
    • myapp1.jar

    看起来像是
    反射的工作
    @kevin我对这个概念非常熟悉,但在您提供的示例中,客户机在编译时绑定到impl,但在我的情况下,客户机和工厂直到运行时才知道impl。这与slf4j方法及其impls.@Ali.Valizadeh类似,在任何情况下,客户机和实现都不需要相互了解。正如维基百科链接所解释的,他们需要一个共享接口或基类。例如,“IJob”或“JobBase”类。但这可能是非常通用的。但是应该有东西为客户端提供该接口的实例。(在本例中为工厂)这是错误的吗?正如wiki解释的那样,“所有变量实例化都需要实现一个创造性模式,作为工厂方法或工厂模式,或者更复杂地使用依赖注入框架。”因此,工厂依赖于编译时的实现。问题是我希望在运行时就有这种依赖关系。@Ali.Valizadeh您的“创造性模式”是您的接口。您可以使用这些方法注入“对象”。但这有什么意义呢?也就是说,客户端必须有一个接口,让它知道如何使用注入的对象。那与工厂无关。如果创建“对象工厂”,则不需要接口。但是这当然不是很有用。我们把实现类的列表放在哪里?
    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();
    }