假设我有这个界面:
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方法有什么意义呢?
感谢您的时间
答案 0 :(得分:3)
接口的要点是避免使用接口的“客户端”代码知道类的实现细节。这对于将来的维护至关重要,因为您正在设计能够在未来的某个时间点替换接口的实现。
如果您的界面包含如何“获取”底层实现的参考,那么为了更新您的代码,您现在需要重写您的界面并重新部署它。基于实现更改的接口中的“更改”,而不是“接口”更改(添加或删除方法)强烈暗示您不在系统设计的原始意图内工作。
默认方法是Java的一个相对较新的补充。过去没有添加它们,因为没有它们,就不可能将实现组合到一个接口中。添加它们允许在接口中定义实现的许多场景,这模糊了接口和抽象类之间的界限。在我看来,这剥夺了其实用程序的界面。
最后,您正在使用它来创建Singleton
,这表明您在面向对象的系统中使用了面向对象的预设计实践。单身人士是引入无范围全局变量的方法。无范围的全局变量使得C / C ++程序很难维护。您最好将代码对齐到传递给需要它的方法的Object中。如果只需要该对象的一个实例,则改进的代码结构只能创建一个实例(一次调用new),并且将清楚哪些方法使用该对象,哪些方法不使用。
答案 1 :(得分:2)
我想知道MyInterface的getSingleton()方法是否应该 存在
您的界面既是界面又是工厂
因此API和实现成为相同的部分。
如果API和实现属于同一个组件(例如jar),实际上它不会改变很多东西。
但是,如果API和实现不在同一个组件中,而是在两个不同的jar中:api
和impl
,则情况就不同了。
这意味着,当您在api
中添加impl
方法时,您的客户必须同时更新impl
和getSingleton()
组件api
1}}。
您没有更改合同,只更改了实施,但客户必须同时更新impl
和api
。
这是不受欢迎的,反直觉的,它违背了分离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
。
只有你的实现应该知道你的界面。