在接口中使用静态单例getter是一种不好的做法吗?

时间:2017-09-01 09:38:57

标签: java java-8 singleton

假设我有这个界面:

    public interface MyInterface {

        static MyInterface getSingleton() {
            return MyDefaultImplementation.getSingleton();
        }

        //declare some methods

    }

和这堂课:

final class MyDefaultImplementation implements MyInterface {

    private static final MyInterface mySingleton = new MyDefaultImplementation();

    static final MyInterface getInstance() {
        return mySingleton();
    }

    private MyDefaultImplementation() {
       //...
    }

    //implement interface methods
}

我想知道MyInterface的getSingleton()方法是否应该存在,或者是否更正确使MyDefaultImplementation及其getInstance方法公开。它是这样的,在接口中使用getSingleton方法有什么意义呢?

感谢您的时间

5 个答案:

答案 0 :(得分:3)

接口的要点是避免使用接口的“客户端”代码知道类的实现细节。这对于将来的维护至关重要,因为您正在设计能够在未来的某个时间点替换接口的实现。

如果您的界面包含如何“获取”底层实现的参考,那么为了更新您的代码,您现在需要重写您的界面并重新部署它。基于实现更改的接口中的“更改”,而不是“接口”更改(添加或删除方法)强烈暗示您不在系统设计的原始意图内工作。

默认方法是Java的一个相对较新的补充。过去没有添加它们,因为没有它们,就不可能将实现组合到一个接口中。添加它们允许在接口中定义实现的许多场景,这模糊了接口和抽象类之间的界限。在我看来,这剥夺了其实用程序的界面。

最后,您正在使用它来创建Singleton,这表明您在面向对象的系统中使用了面向对象的预设计实践。单身人士是引入无范围全局变量的方法。无范围的全局变量使得C / C ++程序很难维护。您最好将代码对齐到传递给需要它的方法的Object中。如果只需要该对象的一个​​实例,则改进的代码结构只能创建一个实例(一次调用new),并且将清楚哪些方法使用该对象,哪些方法不使用。

答案 1 :(得分:2)

  

我想知道MyInterface的getSingleton()方法是否应该   存在

您的界面既是界面又是工厂 因此API和实现成为相同的部分。

如果API和实现属于同一个组件(例如jar),实际上它不会改变很多东西。

但是,如果API和实现不在同一个组件中,而是在两个不同的jar中:apiimpl,则情况就不同了。
这意味着,当您在api中添加impl方法时,您的客户必须同时更新implgetSingleton()组件api 1}}。

您没有更改合同,只更改了实施,但客户必须同时更新implapi。 这是不受欢迎的,反直觉的,它违背了分离api和实现的目的。

答案 2 :(得分:1)

使用第三个提供对象实现的对象更为正确。

赞:DI.getBean(MyInterface.class) -> return myDefaultImplementation

或者:SingletonServiceFactory.getBean() -> ...

示例:

答案 3 :(得分:1)

接口不能是单身人士。实现类可以是Singleton,但这不会阻止接口的其他实现类。因此,接口中名为getSingleton()的方法,表明接口是Singleton,显然是错误的。虽然实现类是Singleton,但工厂方法的目的是使用接口从代码中隐藏此实现,因此尝试通过API导出有关此隐藏实现类的属性的信息(如Singleton特性)是矛盾的。

与接口中的工厂方法相比,它与Stream.empty()或Java 9的List.of()相比有所不同,它们不会告诉底层实现是否为Singleton。它们为专门的实现提供工厂,这被认为是基础,足以成为接口API的一部分。

当考虑在界面中提供工厂时,这也是您的主要考虑因素。这些实现的存在与接口耦合,即使实际的实现类不是这样,所以你总是必须将接口与适当的工作实现类捆绑在一起,即使应用程序可能只使用接口来实现它它自己的。可能有实施值得这样的治疗。但是,如果您希望始终只使用这个单独的Singleton实现而没有其他实现,则根本没有理由使用接口。

答案 4 :(得分:0)

在我看来,错误

您的界面MyInterface不应该了解实施MyDefaultImplementation。 只有你的实现应该知道你的界面。