您现在的位置是:亿华云 > IT科技类资讯
CTO问:Service层真的需要接口吗?
亿华云2025-10-09 03:29:55【IT科技类资讯】8人已围观
简介前几天刷到个问题:Service 层和 Dao 层真的有必要每个类都加上接口吗?这个问题之前简单回答了一波,给出的观点是看情况!今天我们要探讨的问题是:Service 层需要接口吗?图片来自 Pexe
前几天刷到个问题:Service 层和 Dao 层真的需接有必要每个类都加上接口吗?这个问题之前简单回答了一波,给出的需接观点是看情况!今天我们要探讨的问题是:Service 层需要接口吗?
图片来自 Pexels
现在结合我参与的项目以及阅读的一些项目源码来看。如果项目中使用了像 Spring 这样的需接依赖注入框架,那可以不用接口!
先来说说为什么使用了依赖注入框架以后,需接可以不使用接口!
不需要接口的需接理由
我整理了支持 Service 层和 Dao 层需要加上接口的理由,总结下来就这么三个:
可以在尚未实现具体 Service 逻辑的需接情况下编写上层代码,如 Controller 对 Service 的需接调用。 Spring 默认是需接基于动态代理实现 AOP 的,动态代理需要接口。需接 可以对 Service 进行多实现。需接实际上,需接这三个理由都站不住脚!
先说说第一个理由:上层可以在下层逻辑没有实现的需接情况下进行编码!很典型的面向接口编程,对层与层之间进行了解耦,需接看起来好像没有问题。需接
这种开发方式适合不同模块之间是需接由不同的人或项目组开发的,服务器托管因为沟通的成本比较大。同时避免由于项目组之间开发进度的差异而相互影响。
不过让我们回想一下,在一般项目开发里面,有多少项目组是按层来切分开发任务的呢?实际上,大部分的项目都是按照功能划分的。
即使是现在前后端分离的情况,单纯的后端开发也是按照功能模块进行任务划分,即一个人负责从 Controller 层到 DAO 层的完整逻辑处理。
在这种情况下,每一层都先定义一个接口,再去实现逻辑,除了增加了开发人员的工作量(当然,如果代码量计入工作量的话,那开发人员应该也不是太排斥接口的),实际没有任何用处。
如果开发人员想在下层逻辑没有完成的云服务器情况下,先开发上层逻辑,可以先编写下层类的空方法来先完成上层的逻辑。
这里推荐一个个人比较喜欢的开发流程,自上向下的编码流程:
先在 Controller 层编写逻辑,遇到需要委托 Service 调用的地方,直接先写出调用代码。优先完成 Controller 层的流程。 然后使用 IDE 的自动补全,对刚才调用下层的代码生成对应的类和方法,在里面添加 TODO。 等所有的类和方法都补全了,再基于 TODO,按照上面的流程去一个个的完善逻辑。此方法可以使你对业务流程有比较好的理解。
对于第二个理由,就完全不成立了。Spring 默认是基于动态代理的,源码下载不过通过配置是可以使用 CGLib 来实现 AOP。CGLib 是不需要接口的。
最后一个理由是可以对 Service 进行多实现。这个理由不充分,或者说没有考虑场景。实际上在大多数情况下是不需要多实现,或者说可以使用其他方式替代基于接口的多实现。
另外,对于很多使用了接口的项目,项目结构也是有待商榷的!下面,我们结合项目结构来说明。
项目结构与接口实现
一般项目结构都是按层来划分的,如下所示:
ControllerServiceDao对于不需要多实现的情况,也就不需要接口了。上面的项目结构即可满足要求。
对于需要多实现的情况,无论是现在需要,还是后面需要。这种情况下,看起来好像是需要接口。
此时的项目结构看起来像这样:
Controller Service----接口在一个包中
impl ---实现在另一个包里
Dao对于上面的结构,我们来考虑多实现的情况下,该怎么处理?
第一种方式,是在 Service 中新增一个包,在里面编写新的逻辑,然后修改配置文件,将新实现作为注入对象。
如下所示:
Controller Service---- 接口在一个包中
impl ---实现在另一个包里
impl2 ---新实现在另一个包里
Dao第二种方式,是新增一个 Service 模块,在里面编写新的逻辑(注意这里的包和原来 Service 的包不能相同,或者包相同,但是类名不同,否则无法创建类。因为在加载时需要同时加载两个 Service 模块,如果包名和类名都相同,两个模块的类全限定名就是一样的了),然后修改配置文件,将新逻辑作为注入对象。
如下所示:
Controller Service---- 接口在一个包中
impl ---实现在另一个包里
Service2impl2 ---新实现在另一个包里
Dao相对而言,实际第一种方式相对更简单一点,只需要关注包层面。而第二种方式需要关注模块和包两个层面。
另外,实际这两种方式都导致了项目中包含了不需要的逻辑代码。因为老逻辑都会被打进包里。
不过,从结构上来看,实际方式二的结构要比方式一的结构更清晰,因为从模块上能区分逻辑。
那有没有办法来结合两者的优点呢?答案是肯定的,而且操作起来也不复杂!
首先将接口和实现独立开,作为一个独立的模块:
Controller Service --- 接口模块 ServiceImplimpl ---实现在另一个包里
ServiceImpl2impl2 ---新实现在另一个包里
Dao其次,调整打包配置,ServiceImpl 和 ServiceImpl2 二选一。既然 ServiceImpl 和 ServiceImpl2 是二选一,那 ServiceImpl 和 ServiceImpl2 的包结构就可以相同。
包结构相同了,那调整了依赖以后,依赖注入相关的配置就不需要调整了。
调整后,项目结构看起来像这样:
Controller Service --- 接口模块 ServiceImplimpl ---实现在另一个包
ServiceImpl2impl ---新实现和老实现在相同的包中
Dao现在,ServiceImpl 和 ServiceImpl2 模块中的包结构、类名都是一样的。那我们还需要接口模块吗?
假设,我们把 Service 接口模块去掉,结构变成了如下所示:
ControllerService1 --- 老实现Service2 --- 新实现Dao单纯的通过调整模块依赖,是否能实现 Service 的多实现?答案显而易见吧?
不使用接口的缺点
上面给出了不使用接口的理由。不过不使用接口并不是完全没有缺点的,主要问题就是在进行多实现的时候,没有一个强接口规范。
即不能通过实现接口,借助 IDE 快速生成框架代码。对于没有实现的接口,IDE 也能给出错误提醒。
一个不太优雅的解决是,将原来的模块里的代码拷贝一份到新模块中,基于老代码来实现新的逻辑。
所以,如果一个项目需要多实现、且多实现数量较多(不过一般项目不会有多个实现的),则推荐使用接口。否则不需要使用接口。
总结
本文针对 Service 层是否需要接口这个问题,指出需要接口的理由的问题。以及个人对这个问题的观点,希望对大家有一些帮助。
作者:架构思维
编辑:陶家龙
出处:toutiao.com/i6882356844245975563
很赞哦!(73635)
相关文章
- 域名不仅仅是一个简单的网站。对于有长远眼光的公司来说,在运营网站之前确定一个优秀的域名对有长远眼光的公司来说是非常重要的。这对今后的市场营销、产品营销和企业品牌建设都具有十分重要的意义。优秀的域名是企业在市场竞争中获得持久优势的利器。
- 7个 jQuery上手项目,Github超千人star
- JavaScript预解析处理过程原来是这回事
- 2020年非常值得推荐的7种 Kubernetes 日志管理工具
- 3、不明先知,根据相关征兆预测可能发生的事件,以便提前做好准备,赶紧注册相关域名。;不差钱域名;buchaqian抢先注册,就是这种敏感类型。预言是最敏感的状态。其次,你应该有眼力。所谓眼力,就是善于从社会上时不时出现的各种热点事件中获取与事件相关的域名资源。眼力的前提是对域名领域的熟悉和丰富的知识。
- 前端高效开发必备的 js 库梳理
- 11 个超火的前端必备在线工具,终于有时间上班摸鱼了
- 前沿实践:垃圾回收器是如何演进的?
- 4、待所有域名查询结束后可在右侧点击导出结果,即可以excel的文件方式将查询到的结果导出。
- 5分钟掌握Python中常见的配置文件