Java 让每个具体类从接口继承是错误的吗?
这是对Zed Shaw很久以前在他的博客中所做的某些决定的回应 然后,专家们将闲逛到 实现他们燃烧的巴别塔 没有任何评论,非常复杂 模拟启用的测试,确保 单个类有一个接口,并且 以“Impl”结束每个类Java 让每个具体类从接口继承是错误的吗?,java,spring,oop,naming-conventions,guice,Java,Spring,Oop,Naming Conventions,Guice,这是对Zed Shaw很久以前在他的博客中所做的某些决定的回应 然后,专家们将闲逛到 实现他们燃烧的巴别塔 没有任何评论,非常复杂 模拟启用的测试,确保 单个类有一个接口,并且 以“Impl”结束每个类 因为,那是最好的 练习 我同样使用Spring和GoogleGuice,我注意到这些框架确实使用了Impl后缀,但很少使用。在我的代码中,我到处都使用接口,因为有人告诉我,这样可以更容易地模拟,等等。我对这个问题有天真的理解吗?(也许模拟框架可以处理抽象类或抽象类,我不知道。我从未尝试过)对于我
因为,那是最好的 练习 我同样使用Spring和GoogleGuice,我注意到这些框架确实使用了Impl后缀,但很少使用。在我的代码中,我到处都使用接口,因为有人告诉我,这样可以更容易地模拟,等等。我对这个问题有天真的理解吗?(也许模拟框架可以处理抽象类或抽象类,我不知道。我从未尝试过)对于我的具体实现,我选择了Spring约定,即在实现名称前加上单词Default
e.g. BottleOpener (interface) is implemented by DefaultBottleOpener (class)
在这个问题上的最佳做法是什么
UPDATE1我发现从方法返回接口很有用,因为我总是可以返回匿名类 最佳做法是:
- 选择一个惯例并保持一致;及
- 不要过分地将所有东西都实现为一个接口
- 你可以隐藏丑陋的细节 客户代码(例如JPA 要使用的注释、设置器 (仅适用于ORM框架)
- 就像DAO或服务一样,
你可以重新编程
class BeerBottleOpener // life's good
class WineBottleOpener // life's still good
interface BottleOpener; class BeerBottleOpener implements BottleOpener; class WineBottleOpener implements BottleOpener; // now living the life! ;-)
- 这不仅仅是嘲笑。在Spring的例子中,它是关于动态代理和面向方面编程的。这就是Spring处理事务、远程处理和所有类型方面的方式
我为存储库、服务等使用接口,但我不会将接口放在模型对象或任何其他实现可能不会改变的对象上
接口将API与其实现方式分开。如果您的实现没有改变,那么接口就没有多大意义
Zed Shaw是一位出色的作家和开发者,但对他所说的话持保留态度。我认为他所沉迷的一些夸张是为了娱乐价值。他说得有道理(“不要因为某个自称权威的人告诉你这是一种‘最佳实践’”),但他说这是一种半戏剧化的方式。我‘听说’在SmallTalk中,你总是在实际实现之前就开始定义接口。。。所以我想,这真的取决于你想要达到的目的和设计目标 这在很大程度上是一个主观问题。最好的响应可能是尽可能多地启用代码的单元测试,但不要让接口创建妨碍完成任务。如果你的代码很快就被淹没了,就把它删掉
也就是说,我看到过有400个类和400多个接口的代码。仅仅是从一堆糟糕的命名约定中挖掘代码就足以让我感到恐惧。另一方面,我正在处理一个没有接口的第三方专有库。模仿这些对象是一件很痛苦的事。在接口上做得太过火是很有可能的。忽略使用虚拟分派进行每个方法调用的[neglible]性能损失,它还为系统引入了更多选项。它实际上会使软件的调试和安全变得更加困难。如果您的方法/函数接受任何旧接口实现者,那么您已经决定接受该实现者可能错误地实现了接口,甚至可能是恶意地实现了接口。程序/库/框架如何允许变化是设计过程的重要部分 为每件事都提供一个接口(或者更一般地说,为可能会被闲置的灵活性而设计)被称为过度工程。如果您可能永远不会有一个以上的具体实现,那么接口就是膨胀。避免在未使用的灵活性中构建的代码更容易理解,因为如果接口不掩盖您只有一个实现的事实,那么您就知道您要处理的具体类型,并且代码更容易推理
这也是我最喜欢的反对模拟的论点之一:它在代码中引入了人工需求,比如能够有多个实现,而这些实现只有一个“真正”的实现。在对象上有接口,并且对象只能通过接口相互通信,这是一件好事 请注意,我指的是对象,而不是集合或其他本质上是“数据”的东西 然而,让一个类实现“IClassName”或类似的功能,并在整个代码库中使用该模式,反映了对接口概念的理解不足。接口通常应由消费类声明为“嘿,这是我需要的服务。”这样,接口表示两个对象之间的交互,而不是对象对世界的单一视图。它还有助于保持职责分离,因为每个类都处理自己的理想接口,因此有助于保持域逻辑与实现逻辑分离 (编辑) 这实际上是关于间接性和抽象性之间的区别。直接匹配API的接口就是间接接口。直接匹配消费者需求的接口是一个抽象,因为它声明消费者想要做什么,并隐藏如何做的所有信息 Zed Shaw在这方面有一篇很好的文章
我认为,将所有具体类隐藏在接口后面不会真的出错 有些情况下,这是多余的,但它不会花费你很多 甚至可以让域对象实现接口。好处: