在运行时选择一个具体的实现 Java 8

Choose a concrete implementation at runtime with Java 8

我不清楚在选择要实例化的 implementation/subclass 时将 if/switch 放在哪里,特别是考虑到现在接口可以有静态方法时。

假设我有一个服务,一个由接口定义的类型和几个实现。我想最好不要把那个逻辑放在服务中,而是要有工厂方法。但是它应该按照 this answer 中的建议进入界面还是另一个带有参数到类型映射的 class?

把它放在界面中对我来说似乎很自然:

public interface MyInterface
{
    public void doSomething();

    public static MyInterface create(int param)
    {
        if (param == 0)
            return new ImplA();
        else
            return new ImplB();
    }
}

然后只需从服务中调用它:

public class MyService
{
    public void serveMe(int param)
    {
        MyInterface.create(param).doSomething();
    }
}

但我不知道让接口了解其实现或父 class 了解其子类型是否不好。所以

  1. 我应该把那个逻辑放在哪里?
  2. 如果我选择某种类型的子class,情况会发生很大变化吗?

为此使用 Factory。这样你就能维持single responsibility principle。然而,在我自己的一个项目中,interface 定义了一种方法,该方法确定应该使用该特定实现的参数类型。由于这个和使用 Reflections,整个过程是自动化的。 Reflections 查找所有实现给定 interface 的 classes 并将其 'usage-type' 存储在地图中以便快速查找。多亏了这样的解决方案,如果开发人员需要新的实现,他所要做的就是创建它。系统的其他部分不需要其他修改,甚至在工厂 class.

Reflections 具有在编译时存储元数据的良好功能,因此运行时查找正确的 classes 是一眨眼的功夫

你的问题有很多解决方案,我想你已经知道其中的很多了。

静态工厂方法模式

interface Interface {
    public static Interface create(...);
}

这可行,但是它使接口和实现的分离变得困难。接口必须知道所有可能的实现,并且它不是特别可扩展的。要添加新的实现,您需要更改接口。

工厂模式

这本书或多或少是 GOF 的老派:

interface Factory {
    public Interface create(...)
}

这允许您替换工厂(甚至堆栈工厂)。它有——但是——你需要绕过工厂对象的缺点。请注意,使用 Java 8,您还可以使用非常轻量级的基于 lambda 的工厂(参见 https://docs.oracle.com/javase/8/docs/api/java/util/function/Supplier.html

容器

另一种解决方案,虽然它可能相当重量级,但将对象的构造留给容器框架。在这些情况下,容器提供您的对象工厂。对象的实际类型留给配置。 Spring 和 Java EE 在这方面做得很好。还可以结合 依赖注入 来增加效果。

我能想到的就这些吧