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

13

我不清楚在选择实现/子类实例化时,应该把 if/switch 放在哪里,尤其是考虑到现在接口可以有静态方法。

假设我有一个服务,由一个接口定义类型和一些实现组成。我想最好不要把逻辑放在服务中,而是使用工厂方法。但是它应该放在接口中还是像这个答案建议的另一个带有参数类型映射的类中呢?

对我来说,把它放在接口中似乎是自然的:

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
你可能在寻找 https://dev59.com/r0fRa4cB1Zd3GeqP6BV6 吗? - dhke
类似这样的东西,但是如果避免使用工厂类并将其放在接口本身中是否是一个好主意。 - user3748908
2个回答

8
请使用工厂模式来实现。这样,您将能够维护单一职责原则。在我的一个项目中,接口定义了一个方法,用于确定应该使用哪种类型的参数来使用特定的实现。由于这个方法和使用反射,整个过程都是自动化的。反射可以找到所有实现给定接口的类,并将其“使用类型”存储在映射中以进行快速查找。由于这种解决方案,如果开发人员需要新的实现,他只需创建它即可。在系统的其他部分甚至不需要在工厂类中进行任何其他修改。

反射具有在编译时存储元数据的良好功能,因此运行时查找适当的类是眨眼之间的事情。


由于这样的解决方案,如果开发人员需要新的实现,他只需创建它即可。但是,他或其他人需要定义选择实现的标准,对吧?这些标准放在接口中吗? - user3748908
是和否 - 接口强制实现类通过声明某种方法(例如 getProcessingType)来提供这样的标准。当为新的“处理类型”创建实现时,开发人员将在创建它时提供标准。 - Antoniossss
回到我的问题。你提出的是拥有一个Factory类,其中只有一个静态方法,对吗? - user3748908

3

我觉得你已经知道了很多解决方案,针对你的问题有很多解决方法。

静态工厂方法模式

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做得很好。还可以与依赖注入结合使用以获得额外的效果。
至少这些是我能想到的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接