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. 如果我选择一种类型的子类,那会改变很多吗?
4

2 回答 2

8

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

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

于 2015-03-20T15:48:55.840 回答
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 在这方面做了很多工作。还结合依赖注入以增加效果。

这些至少是我能想到的。

于 2015-03-20T15:58:44.743 回答