使用 Java 8 在运行时选择具体实现

在选择要实例化的实现/子类时,我不清楚在哪里放置/,特别是考虑到现在接口可以具有静态方法时。ifswitch

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

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

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();
    }
}

但我不知道让接口知道它的实现,或者让父类知道它的子类型是不好的。所以

  1. 我应该把这个逻辑放在哪里?
  2. 如果我选择某种类型的子类,这会改变很多吗?

答案 1

用于此。这样,您将能够维护 .然而,在我自己的一个项目中,定义了一种方法,该方法确定应该使用此特定实现的参数类型。多亏了这一点和使用,整个过程都是自动化的。 查找实现给定的所有类,并将其“使用类型”存储在映射中以进行快速查找。多亏了这样的解决方案,如果开发人员需要新的实现,他所要做的就是创建它。系统的其他部分不需要其他修改,甚至在工厂类中也不需要。Factorysingle responsibility principleinterfaceReflectionsReflectionsinterface

Reflections具有在编译时存储元数据的不错功能,因此运行时查找正确的类只需眨眼间


答案 2

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

静态工厂方法模式

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在这方面做得很好。还与依赖注入结合使用,以增加效果。

这些至少是我能想到的。


推荐