1
RedBeanIce 2021-03-12 10:18:32 +08:00
大部分系统没用。。。
|
2
hello2060 2021-03-12 10:21:32 +08:00
接口那肯定是因为要复用啊,把公用的部分抽取出来,没这个需求就不用呗。
|
3
justNoBody 2021-03-12 10:22:35 +08:00 2
如果你这个类的工作简单,且业务上目前没有什么需要扩展的,没有什么变化点,我觉得是可以不写接口的。
但是,如果这个 service 会存在多种实现的时候,比如你的 service 是需要调用运营商的短信接口,然后你们对接了多个运营商,这个时候接口就非常有必要了。 有了这个接口以后,其他同学只需要根据你定义的接口,传入必要的参数,选择一个合理的实现(或者你用策略模式封装一下),就可以非常简单的发出短信。 个人见解,欢迎讨论 |
4
awesomeMen OP @hello2060 为什么复用就要加个接口?直接在 service 层写方法不行吗?
|
5
yeqizhang 2021-03-12 10:24:21 +08:00
面向接口编程... 主要是接口代理、接口继承、极小的可能直接改成 rpc...
|
6
wakzz 2021-03-12 10:24:59 +08:00
绝大多数系统用不上接口抽象,后来就很少用接口了,除非一开始就确定这快逻辑有多个实现类所以要抽象个接口出来。
|
7
hafuhafu 2021-03-12 10:27:48 +08:00
你要是保证项目所有 service 从现在到将来都只有一个实现,那肯定没用啊。
这个就是个规范而已,约定优于配置。你喜欢的话不要 service 都行。而且业务系统这种基本类和接口都是自动生成的,在意这个干吗...不就接口加一个方法,实现类实现一下的事。 |
8
KarmaWu 2021-03-12 10:28:01 +08:00
看情况,假设要区分多个版本的接口,须有不同的实现类
|
9
securityCoding 2021-03-12 10:29:01 +08:00
1. 如果都是内部自己调用,那没有必要,一个 class 撸到底就行
2. 如果有外部 rpc 调用的话,还是定义一个接口方便打包到 client-sdk 给别人 |
11
chendy 2021-03-12 10:35:07 +08:00
大部分业务场景用不上,能想到的需要用到的场合:
1. 上古系统没有 cglib 之类的只能用 Proxy 所以必须接口 2. 需要多个实现 3. 要分发 service 层代码 |
13
soupu626 2021-03-12 10:38:03 +08:00
基本原理就是,大家先约定好,要什么参数,什么返回,然后就可以不关心底层细节和上层逻辑,各干各的就行了,还有就是结对的时候,便于测试,定好接口,一个写实现,一个写测试,本质上是为了解耦
但是现在大家都是一个人一把梭,就是个象征意义,可以不加 |
14
Macolor21 2021-03-12 10:43:21 +08:00 via iPhone
提问之前善用搜索引擎,了解下提问的艺术,这个问题在 StackOverFlow 已经有人提问,并且多个答案很好的解释了。/questions/55087578/do-i-really-need-to-create-interfaces-in-spring
总结来说,这样的写法是用于扩展用(利用 DI ),你常规理解的用法,这个 service 有不同实现,然后就是 DI 的好处了。 但如果你的 service 不需要另外的实现,你可以不用写,Spring IOC 也能将你的 service 注入到其他类中。现在微服务盛行,没啥机会让你为一个 service 写多个实现了。 但是基于接口,你可以在测试时,不使用生产的业务,通过写一个 Mock 实现,配置不同的配置文件,来测试你的这个 service 接口。 |
15
zjsxwc 2021-03-12 10:45:47 +08:00 9
用 interface,是为了能够方便地在屎山上拉屎啊,
不用 interface,你需要挖开老屎,看老屎里面有啥,用来 interface,你只管在老屎上面拉新屎。 |
16
xlui 2021-03-12 10:53:19 +08:00
先说结论,有必要。
就算只有一个实现类,也应该保留接口。这种情况下,通过查看接口,我能很快的找到对外暴露的方法,后续维护重构都很省心。 如果不保留接口,那我在查看类的功能时候就得遍历所有的 public 方法,时间一长,转手的人一多,这个类就会无限膨胀下去,最终变成屎山。 |
17
zjsxwc 2021-03-12 10:58:00 +08:00
interface 无非就是给屎打上标记而以,这是黑色的屎、这是黄色的屎,这是硬的屎,这是稀的屎,
这个坑只能拉 又黄有稀的屎,我就拉 又黄有稀的屎,我 tm 才不管你这个坑里面有什么屎,以前有谁在这个坑里面拉屎。 如果屎没有各种标记分类,就相当于,这是张三拉的屎,这是赵四拉的屎,tm 的这个坑居然只能张三来拉屎,我要拉屎,只能让张三来代替我拉屎了,张三又不在,怎么办啊,只能把我变成张三,很累的好不。 |
18
zjsxwc 2021-03-12 11:01:38 +08:00
当然,我可以继承张三啊,我就又可以拉屎了,可是很多时候,我虽然继承了张三,但我看不惯张三,张三吃素,我吃肉的,根本就是格格不入
|
20
zjsxwc 2021-03-12 11:13:18 +08:00
当然,你可以一个屎填坑,这个坑永远只能拉这个屎,有需求,就改造这个屎本身,也就是楼主主题里说的。
我明明能一个屎完事,这个 final 屎就是牛逼!没有毛病。 |
21
uselessVisitor 2021-03-12 11:24:51 +08:00
接口顶层,比如说 IDeviceService 然后可以有多个实现类 DefaultDeviceServiceImpl 、xxxDeviceServiceImpl ... 引用的时候用 @Resauce 指定具体哪个实现类?我觉得这样比较好。但是实际工作中,都是一个接口实现类撸到底
|
22
zjsxwc 2021-03-12 11:28:37 +08:00
先贤们是拒绝改造这个屎本身的,
改造本身意味着你之前拉的这个屎,“有 bug”,只有不完美的屎才需要被再次改造, 这是对你拉屎技术的侮辱, 所以讲究的先贤们提倡用 interface,避免改造屎本身,除非真有 bug 才去改造屎本身,别动老屎! 当然不讲究的我,改个屎而以,给钱就行! |
23
clf 2021-03-12 11:46:50 +08:00
JDK8 接口可以使用 default 关键字在接口里提供默认的抽象方法的实现:
依据这几个特性,我可以封装一些泛型接口,提供可复用的泛型方法,实现类里只需要写业务部分的代码,由于大部分的服务都是继承于相同逻辑的接口,这样无论是基本的异常处理、日志记录、逻辑删除控制等等都能统一,并且在未来对这种统一的逻辑进行调整的时候,也只需要修改一个地方。如果某种业务有其它的逻辑,可以重写接口的默认实现。 接口可以多重继承(一个类实现多个接口): 在微服务场景中,一个服务可能被其它微服务调用,也可能被自己这个微服务里的其它 Service 类或者 Controller 调用,两边能调用的方法有相同的,也有不同的,通过提供不同的接口来控制方法的可见性。 |
24
HelloWorld556 2021-03-12 11:54:00 +08:00 3
这是一篇有味道的文章
|
25
xuanbg 2021-03-12 11:55:20 +08:00
没有逻辑上的必要性,但有工程上的必要性。一来我可以只写接口,别人去写实现。二来方便复制粘贴生成其他代码的基本结构及注释。
|
27
ychost 2021-03-12 12:36:26 +08:00
个人觉得最佳实践,当需要提供 RPC 调度的时候可以加接口(毕竟 RPC 要提供 二方包),当内部相互调用的 Service 就没必要写,啰里啰嗦,改起来也麻烦,除非有那种根据配置切换 Service 的需求,但是这种一般通过 SPI 来做
|
28
lff0305 2021-03-12 12:41:05 +08:00
写个接口再写实现是基于以下的原因:
1. "面向接口编程"的实践 2. spring aop, 很久以前基于 jdk 动态代理的实现必须要接口,但是后来 cglib 稳定之后就可以不需要。所以接口-实现这个习惯就保留下来了。 |
29
liuzhaowei55 2021-03-12 12:58:37 +08:00 via Android
给自己业务用就没必要,对外开放就有必要。
|
30
CrazyBoyFeng 2021-03-12 13:48:10 +08:00
我给三楼的举例补充一下代码说明:
``` 运营商 Interface 运营商=null; switch(用户.get 运营商()): case 移动: 运营商=new 移动(); break; case 联通: 运营商=new 联通(); break; try{ 运营商.发短信(); }catch(短信失败 Exception e){ 运营商.打电话(); } ``` 这段代码不用接口的话,实现相同功能可能需要写出许多重复代码。 |
31
cmsyh29 2021-03-12 13:50:24 +08:00
额。我以为这是以前只支持 JDK PROXY 的遗留...
|
32
vate32 2021-03-12 14:21:55 +08:00
我觉得,如果只是一个定义只有一个实现这种方式的话,没有必要搞了,费事也令人费解。但是倒是可以使用这种接口+实现的结构,实现一些设计模式,比如说这两天就在用的责任链模式。。。
|
33
kifile 2021-03-12 14:47:04 +08:00
多人开发的时候是有意义的,找一个人把接口定义写了,后续别的同学基于接口定义,各自写各自的逻辑,挺好的。
各种测试逻辑也可以同步开始 |
34
oneisall8955 2021-03-12 15:30:54 +08:00
emmm,上个月才看到类似帖子 /t/747463
|
35
robinWu 2021-03-12 15:33:11 +08:00
你需要 mock 单测吗?
|
36
litchinn 2021-03-12 15:59:50 +08:00
这是个历史遗留,完全可以不用
|
38
sha851092391 2021-03-12 16:20:02 +08:00 1
首先看你的 service 是什么类型,是业务逻辑类型还是外部集成类型(例如调用 xx 短信渠道发短信)。
业务逻辑类型其实是基本上不需接口,如果非得考虑什么接口多半是因为考虑到以后 service 变成 rpc 调用,但是实际上就算变成 rpc 调用,业务逻辑类型的上层也会再包装一层,所以基本上不会用接口。 外部集成类型因为会有多种实现的可能性,考虑到扩展实现所以会使用接口来做。 |
39
superliuliuliu1 2021-03-12 16:24:28 +08:00
@zjsxwc 味道十足
|
40
hehe12980 2021-03-12 17:40:24 +08:00
我个人认为 service 这层一定是要写接口的,最主要是为了抽象,当然有很多开发的人根本不明白写接口背后的意义,大部分都是要求写就写,先说结论写接口是为了抽象(可能你觉得是废话),随便假定一个场景把,比如我有一个 IA service 接口这个接口,处理一个很纯粹的业务逻辑。
场景 1:比如说步骤 1.是操作数据(必须要调 IBService,ICservice) 步骤 2.是保存数据,一开始小张这么写,它一个个调 IBServcie.operate,ICService.operate,保存也是如此,有一天业务变更,突然 IDService 也要存,继续改代码,这个时候就没有想过把公共方法抽出来比如叫 ISaveService,IOperateService,注入到 list 里,遍历去操作,去存。以后再加其他的 IEservice 这一块的代码不用动了。只需要写 IEservice 的逻辑 场景 2:再比如说步骤 1,是操作数据(根据类型,可能调 IBService,也可能要调 ICService,但是只调其中一个就能把业务完成了), 步骤 2 是保存数据,小张写了个 if,else 去干 后面随便类型的增多 if,else 越来越长就跟屎山一样,如果一开始就把类型做成特征比如说 IOperateService 定义两个方法 supportType ( type )以及 operate(params) 然后 IBService,ICService 去实现这个 IOperateService 接口,注入这个 List<IOperateService> list 遍历去找适配的类型的 Service, 去 operate 。 后面再加更多的类型 这一块也是不需要动的。 例子有很多很多,抽象很重要,觉得不重要的,武断的说一句,大概率是个菜鸡。 |
41
sha851092391 2021-03-12 17:42:44 +08:00
@sha851092391 还有一种情况业务方法也要使用接口,就是你的 service 写太多乱七八糟的方法了,这时候可以通过接口去规范提供对外的调用方法。
|
43
linbiaye 2021-03-22 13:12:41 +08:00
在 spring 的和 cglib 的加持下,没有必要。如果一个 interface 只有一个实现,这种抽象的意义在哪里?
|