JavaWeb 中的接口层到底有什么用

2020-03-08 1660点热度 0人点赞 0条评论

提出问题

我觉得做过 Java Web 项目的程序员,代码数量敲到一定程度的时候,都会产生这样的疑惑:MVC 层中的 Service 层,Dao 层的接口到底有什么用?是否是为了使用接口而使用接口?

不用接口并不代表就不能解耦,就不是 OOP 。

尤其是在事实上,99% 的场景都是接口与实现类严格一一对应的。在这种情况下,接口究竟有什么意义?

是为了使用 JDK 基于接口的动态代理吗?但基于 CGLib 的动态继承也同样可以实现 AOP,并且 Spring 本身也对两种技术都提供了支持,所以技术上的理由也同样是不充分的。

使用接口的好处

我们来看看我们通常可以想得到的,使用接口的好处:

为每个 Dao 层声明接口的好处在于:

  1. 可以在尚未实现具体 Dao 方法时就编写上层代码,如在 Service 层中对 Dao 的调用;
  2. 可以为 Dao 提供多个实现, 例如有 JDBCDao 实现,MyBatisDao 实现,而不需要修改上层代码,只需要简单的在 Spring 中控制 Dao 对象的注入即可。

Service 接口:

  1. 可以在尚未实现具体 Service 情况下编写上层代码,如 Controller 层对 Service 的调用;
  2. 可以对 Service 提供多实现。

另外,使用接口对于测试代码也是有好处的。测试者不需要关注方法的具体实现,可以基于接口直接提供 Mock 方法。所以使用接口对于快速实现流程上的测试是有好处的。

上面说了一些使用接口的有点,但是好像都并不是很明显。只要我们的实现与接口一一对应,实现类也完全可以完成这些职责。

之前也说了,不用接口并不代表就不能解耦,但使用接口确实可以更好地实现解耦。尤其体现在:

  • 接口与实现是不同模块,或不同团队提供(虽然并太常见);
  • 开发框架。

框架开发应该是比较常见的必须使用接口的案例了,比如开发 Spring,Struts 。这时你没有任何实现代码,也必须面向接口开发。

使用接口的坏处

相较于模棱两可的优势,使用接口的坏处可以说非常明显了:

  • 重复代码,增大了编写,维护,调试成本;
  • 增大系统复杂度,对系统的理解变得困难。
绕过接口的最大坏处是不可控的类信息暴露控制

引述知乎上一个真实的案例(链接见文末):

比如我们打算用 AOP 来实现 service 方法级别的缓存,并用 annotation 来标记需要缓存的方法和缓存控制声明。

如果使用接口层,实现就很简单了,只需要在接口的方法声明上标记 annotation 就可以了。

如果没有接口呢?显然,我们只能把 annotation 直接标记到类方法上。看起来没啥区别是吗?但是,直接在类方法上标记可能会导致一个意外的错误,就是开发者有时会将 annotation 标记到 private 方法上去。

很多同学这时候应该已经会心一笑了,基于 CGLib 的类继承方式实现的 AOP 是不能在 private 也不能在 final 方法上生效的。所以,开发者可能会自以为已经缓存了一个很复杂的方法实现,但实际上却完全没有生效。

反过来,这样的错误,在基于接口的方式下,是几乎不可能出现的。开发者如果发现需要缓存一个很重的 private 方法,要么会很省事的把这个方法改为 public 并添加到接口,或者更有责任心的考虑一下,是否需要修改接口设计让整个 Service 的体系结构更加合理。

「上面说过的错误,我们实际上是的的确确出现过的,但这个错误,是在我们一开始决定不使用接口的情况下就非常清楚这个风险的,我们在事前经过讨论,认为这个风险是可以接受的,同样在工程实践中,即使真正出现了这样的错误,我们讨论评估之后的结论仍然是,我们可以接受偶尔出现这样的错误,所以我们决定继续这样的设计风格。」

作者选择不使用接口层的主要理由有:

  1. 我们是小团队,大家的技术水平相对较高且平均,出现这样的错误情况并不多见,从概率上可以接受。
  2. 同样,因为是小团队,所以虽然没有刻意的做代码 review,但是在编码的同时代码的交叉 review 是相当频繁的,所以,即使出现错误,发现的概率也是很高的。
  3. 我们不是面向企业的业务系统开发,我们是做公开的 service site,是面向互联网的服务,我们的业务逻辑变更非常频繁,所以,没有接口的情况下,我们可以少写代码,也更易于变更,少了一个接口抽象层,代码阅读体验也大大提高,这点让我们觉得更加重要。

反之,大多数 Java Web 项目开可能都是面向企业应用的开发,开发人员的技术水平可能参差不齐,或者是非常大型的开发团队。这两种情况下,意外错误的风险都会被放大,而通过接口来约束并保证不出现意外就显得更加重要了。

It depends

项目中是否一定需要接口层,总的来说还是需要具体问题具体分析。
这取决于项目团队的技术能力,团队规模,以及对开发成本和开发质量的平衡考量。
大部分情况下,还是推荐遵循面向接口的开发流程,通过约束减小错误对系统的影响。

参考文章:

SilverLining

也可能是只程序猿

文章评论