最近看了几个 web 项目, 不明白的是, 为什么到处都是 interface? 而且很多 interface 只有一种实现?
俺理解的是, 只有在抽象的情况下, 以及可能有多种实现的情况下, 才需要 interface, 比如一个
IUserRepo 表示用户数据的存储, 而存储方式可能是有多种情况, 为了不在业务层耦合到具体的存储方式, 所以使用接口没问题.
但像以下这种
IUserService
UserSeriveImpl
对于这种业务层为什么还要抽象一种接口? 俺好像没见过 IUserService 这种接口有多种实现的情况?
1
janus77 2022-05-26 15:23:32 +08:00
面向接口编程是这样的
|
2
dcalsky 2022-05-26 15:25:43 +08:00 3
如果经常写测试你就会发现除了正常的实现,还有一种叫 mock 实现。
结论:写 interface 是方便测试的时候 mock 以及今后多实现拓展;但是现实却是很多人压根不写测试,活生生把 interface 玩成样板模板。 |
3
eote 2022-05-26 15:26:01 +08:00
使用 interface 进行 AOP 效率比较高,因为对外暴露的方法已经确定了。还有就是 web 领域外包遗毒,DDD 模式深入骨髓
|
4
Oktfolio 2022-05-26 15:30:43 +08:00
Spring 在 AOP 的时候,类实现了接口就使用 JDK 动态代理,没有则使用 CGLib
|
5
zzzkkk 2022-05-26 15:31:14 +08:00
那种设计已经成了业界标准
更恶心的是 有人竟然把这套东西搬到 php 这套东西最没技术含量 |
6
unco020511 2022-05-26 15:39:39 +08:00
因为这是毒瘤模板
|
7
pavelpiero 2022-05-26 15:40:15 +08:00 via Android
😂
|
8
pavelpiero 2022-05-26 15:41:30 +08:00 via Android
你好,其实你举例的 userservice 最贴近这种场景了,因为多样化的登录方式会涉及到不同的实现,比如密码登录,扫码登录,刷系统授权登录。
|
9
banmuyutian 2022-05-26 15:45:40 +08:00
因为大部分是毒瘤模板+1
|
10
crysislinux 2022-05-26 15:49:02 +08:00 via Android
这就叫依赖反转
|
11
asanelder OP @dcalsky #2 应该是 mock 的 repo 吧, 比如, 测试的时候, 可能不依赖真实的数据库, 而是依赖内存存储之类的, 本来就是要测试业务逻辑的, 不应该 mock UserService 这咱吧...
@Oktfolio #4 第二种不是效率更好么? @zzzkkk #5 一直没找到这种标准是从哪里来的... 找不到出处啊, 铁子 @pavelpiero #8 俺理解的是, 如果登陆方式要抽象的话, 设计一个 ILogin 接口就好, UserService 依赖这个, 而不必把 UserService 也搞成接口 |
12
JaguarJack 2022-05-26 15:52:07 +08:00
明明业务里面只有一种实现,为什么还需要定义 Interface ?我也有这样的疑问
|
13
yohole 2022-05-26 15:55:33 +08:00
对于大型项目或者可预见会持续迭代的中大型需求,面对接口编程没有错,成本也是基本客户忽略
但是实际情况下正如你所说的,很多系统或者需求可能在第一次上线之后,基本很少改动或者不会有变化了,这种情况下完全可以直接写实现的,不需要任何接口的实现 如果一定要扯远一点,这有可能是因为 JAVA 从诞生的那一刻的定位和宣传都是企业级,可维护性和可扩展性可能是要放首位的 然后很多后来者不断受着各种设计模式和大量开源项目的影响,于是就慢慢变成现在的"标准"和事实了 |
14
Oktfolio 2022-05-26 15:56:42 +08:00
@asanelder JDK 动态代理从 1.8 开始就比 cglib 高了吧。不过大多数人不会考虑这个问题,按照“传统”来就是了
|
15
makelove 2022-05-26 15:58:08 +08:00
@zzzkkk php 作者绝对是个脑残 java 粉,连语法都抄 java,甚至以前半官方的 Zend 框架都一股子恶臭 Java 味。
|
16
LeegoYih 2022-05-26 16:00:30 +08:00
有没有一种可能,人家用 interface 是为了 RPC 准备的
|
17
offswitch 2022-05-26 16:04:19 +08:00
你的理解是对的,很多人不懂,就喜欢这样呗,没办法。
|
18
wolfie 2022-05-26 16:06:14 +08:00
面向 kpi 设计带来的习惯,只有一个实现不需要这么做。
系统性搞过架构的毕竟少数。 |
19
statumer 2022-05-26 16:06:36 +08:00 via iPhone 2
这种做法对于项目管理是有好处的,不要觉得用接口就是为了替换实现。
如果搞个 Interface ,开发者就只能暴露方法,不会乱暴露对象成员变量,减少 caller 做 hack 的可能性。 |
20
elintwenty 2022-05-26 16:08:41 +08:00 2
某些情况比如 rpc 需要 interface 、或低版本的一些实现方式,而且 interface 就算只有一个实现类的情况,可以起到 中高级开放人员编写 interface 交给其他人开发 的管理作用,或者更方便的看提供接口,直接看实现类代码量较大(虽然这个可以被插件或 ide 取代)
|
21
BBCCBB 2022-05-26 16:08:52 +08:00
为什么我在只有一个实现的时候就不搞?
|
22
mgcnrx11 2022-05-26 16:09:13 +08:00 2
经历过麻木写 Interface ,然后变成觉得都是一种了就不写 Interface ,到最后维护的项目需求确实增长超出预期又退回去老老实实写 Interface 的阶段
这种设计模式嘛,你不知道后面会不会有用得上的时候,当真的用得上多种实现,就会庆幸当年没有偷懒写一个 Interface 了 |
23
MicroGalaxy 2022-05-26 16:13:14 +08:00
模板吧,我见过项目绝大部分都是只有一个实现。况且我写自己项目的时候都不写 Interface ,真的用不上
|
24
Bingchunmoli 2022-05-26 16:15:41 +08:00 via Android
代码生成的,也方便后续自己写其他实现..
|
25
Bingchunmoli 2022-05-26 16:20:15 +08:00
1. Spring 在 AOP 的时候,类实现了接口就使用 JDK 动态代理,没有则使用 CGLib
2. service 不写接口 有可能被 leader review 的时候打回来 3. 代码生成无成本 |
27
zzzkkk 2022-05-26 16:29:21 +08:00
|
28
lengyuqu 2022-05-26 16:31:05 +08:00
因为这样的模板开发过程中不容易出错,而且可以大量使用码农投入开发。
任何大规模普及的开发模式一定不是出于技术角度,而是商业运行的角度。显然这个更符合商业运作 |
29
lanlanye 2022-05-26 16:34:46 +08:00
现实确实是大部分接口只有一种实现,但对外使用接口能让你在更改实现的时候更好做一些,另外就是上面提到的需要 mock 的场景,这个可能更常见。
在 Golang 里还有避免写 * 这个理由…… |
30
SMGdcAt4kPPQ 2022-05-26 16:35:33 +08:00 via Android
有人用 interface 做 mixin 吗?
|
31
nicevar 2022-05-26 16:35:56 +08:00
再怎么吐槽,这都是 Java 一个非常好的地方,就是再烂历史包袱再重的项目随便换个人来接手,还能干得下去,换成其他语言实现的,都不想瞧一眼。
|
32
cubecube 2022-05-26 16:37:01 +08:00
框架用 interface 无可厚非,业务代码实现 interface 不香么
|
33
Huelse 2022-05-26 16:41:05 +08:00
留下足够丰富的信息确保项目可以持续迭代,哪怕是 shi
|
34
chendy 2022-05-26 16:43:05 +08:00
repo 用接口,方便多实现 / mock
往上的其实直接 class 就行了 spring 很早就自带 cglib ,没接口不能出代理的时代已经过去了…… |
35
cheneydog 2022-05-26 16:47:03 +08:00
我觉得 java 的 Interface 挺好的,语法上也没强制要写呀,只是习惯上要写,我也写,默认实现怎么快怎么来,期待着未来能改进。
我也希望 nodejs 中能写 interface ,但是不想用 ts 。 |
36
darksword21 2022-05-26 16:52:32 +08:00 via iPhone
如果突然某一层要换的话确实很方便,比如数据库,上层基本不用变,当然在公司里一般写完也不会变了
我是说我在 go 中这么写,java 没经历过 |
37
guxingke 2022-05-26 16:53:58 +08:00 1
如无必要 勿增实体
--- 不妨从自己做起,没必要声明的时候就不声明呗。 毕竟真有必要的时候,再抽出一个接口并不困难。 |
38
Kaiv2 2022-05-26 16:56:42 +08:00
说下这种模式的优点
IUserService UserSeriveImpl 我开发一个依赖 UserService 的模块, 你负责 UserService 模块的开发,但是还没实现。你可以先提供接口给我。 类似的 ( dubbo 服务也是这样) |
39
slimhigh 2022-05-26 17:04:20 +08:00
你的理解是对的。大部分情况下是没什么用的,大家生搬硬套罢了。
|
40
retrocode 2022-05-26 17:06:12 +08:00
规范嘛, 恶心是真滴恶心, 不过好处是有这么一套通用甚至垄断的规范在, 不至于太恶心,不然高情商点百花齐放,低情商则神魔乱舞,一个人一套规范,天天吵最佳实现谁也不服谁那才是真的恶心了
|
41
ThinkCat 2022-05-26 17:09:11 +08:00
如果不涉及到多实现,那可以不用 interface ,直接写 class 实现就行了。但是如果明确在后期存在扩展的情况,一定要定为接口,避免后期大范围的修改代码
|
42
potatowish 2022-05-26 17:14:21 +08:00 via iPhone
有规范就容易产生模板式的代码,但是没有规范,大家各写各的,不利于团队开发
|
43
forbreak 2022-05-26 17:16:42 +08:00
大部分情况下没用,但是一旦要用,你之前写了跟没写 差距久出来了。 我只一个旧项目,改 rpc 调用,之前写了 inteface 很容易久迁移好了。没写的话,就得重新写一遍。。
|
44
FreshOldMan 2022-05-26 17:21:13 +08:00
不容易出错
|
45
FreshOldMan 2022-05-26 17:21:33 +08:00
相当于注释了吧
|
46
panpanpan 2022-05-26 17:23:15 +08:00
虽然 Spring 在 AOP 的时候,类实现了接口就使用 JDK 动态代理,没有则使用 CGLib
但是实际上大家都用 springboot, springboot2.0 之后默认情况下不管你有没有接口统统用 CGLib |
47
yazinnnn 2022-05-26 17:30:54 +08:00
写 spring 不会写,都是单实现,基本不会写接口
写 vertx 时会, 因为会用到 service proxy 和 codegen 基于 future 的接口 client, 会把 reactive 的 client 给你包好 基于 future 的接口服务, 会把 eventbus proxy 生成好 现在改用 quarkus,然后又不写接口了.... |
48
lixiaohui0812 2022-05-26 17:34:36 +08:00
test + 多个实现
|
49
v2orz 2022-05-26 17:38:28 +08:00
因为我真的见到过有多种实现的情况
|
50
mekingname 2022-05-26 17:41:49 +08:00
写 java 的人,骨子里就喜欢过度设计。他们很多人写的代码一辈子都不会重构或者增加新的功能了,但是他们总是抱着:未来要增加新的功能,所以要面向接口来设计。
|
51
sparky 2022-05-26 17:48:54 +08:00
面向接口而非实现的编程思想
越抽象、越顶层、越脱离具体某一实现的设计,越能提高代码的灵活性、扩展性、可维护性 |
52
dajj 2022-05-26 18:00:27 +08:00
无脑重复前人的代码, 毒瘤模板而已
|
53
yangyaofei 2022-05-26 18:25:18 +08:00
很多原因吧, 比如: 1. 被诟病的 封装, 设计设计设计, 设计模式啊, blbla... 2. 正常原因 java 不能多继承,只能用 interface 来做(其实还好) 3. 卷 4. 包屎
|
54
asanelder OP |
56
cool4food 2022-05-26 19:34:28 +08:00
对 OO SOLID 稍微理解深入一点的话,应该就不会有那种尬黑吐槽的言论了
|
57
RadishWind 2022-05-26 19:41:30 +08:00
之前接手过一个屎山就没有 interface+impl 结果有个方法很慢 找到后没法使用 @Cache 注解进行优化 Spring 很多特性是依赖动态代理的
|
58
icylogic 2022-05-26 19:42:40 +08:00
超出必须的设计,无非就是方便调试 /测试 /扩展,如果未来一段时间内,你发现你实现新需求 /调试 /测试的时候,需要从这里继承实现一个不一样的,那说明这设计至少算不上错,如果你发现你这项目到死都没有过这种事,那就是过度设计,要么是思维上懒惰,要么是对未来需求预估错误。如果你发现你可能需要,但你觉得有更好的方式,那就是你们团队之间选择谁来适应谁的问题。
|
59
haah 2022-05-26 19:46:25 +08:00 1
为啥 C/C++er 要写头文件呢?
|
60
CoderGeek 2022-05-26 20:05:34 +08:00
看下 jdbc mycat 的源码 - -
|
61
luzemin 2022-05-26 20:18:41 +08:00
1. 为了实现 OOP SOLID 中 D ,依赖抽象而不依赖具体,为了 N 年后的随时换掉具体实现而规划
2. 方便测试 3. 约束方法名称:具体实现类必须继承并且实现同名方法 以上都是理论,实际往往偏差比较大,基本是因为“模版就是这样”“业内都这样”而跟着做的。 |
62
vincent7245 2022-05-26 20:39:04 +08:00
规范,规范,还是 TMD 规范,这就是为什么 java 可以做超级大型的项目。当你一个人做项目的时候可以随意写,当四五个人做项目的时候,一般的口头沟通就可以了。当几百个人同时做一个项目的时候,没有规范你啥都做不了。当你做过大型项目你就明白了。这里的大型项目是指代码至少 10W+起步
|
63
ration 2022-05-26 20:39:49 +08:00 via Android
面向对象基本都是这样,除了多个实现,依赖注入外,还有其他好处。比如你可以只看接口就知道实现了什么功能,而看具体的类就有一大堆代码了。接口这种东西一开始是来源于硬件而不是软件。
|
64
qq1009479218 2022-05-26 21:44:10 +08:00
不做单测吧
|
65
qbmiller 2022-05-26 22:08:31 +08:00
大多数项目用不上.
大型项目确实要, 防止写飞 实战为准. 确实没必要 别的语言从没这么多破事 |
66
Rocketer 2022-05-26 22:36:34 +08:00 via iPhone
各种设计模式都是为了方便项目规模成长的,所以绝大多数“没必要”都是因为团队 /项目还不够大。
等规模大到设计模式显示出优势时,大概率就很难改了,最后变成💩山。 当然,一直写那种代码的程序员也不会意识到设计模式的优势,他们宁可把代码复制粘贴到一百个地方,也不愿把代码写得一劳永逸。只要不跳出舒适区,我就是舒适的😄 |
67
vone 2022-05-26 22:40:47 +08:00
方便单元测试和多实现。
但是现实是没卵用,因为这些复制粘贴的垃圾代码既没有单元测试也没有多实现。 |
68
HiShan 2022-05-26 22:42:37 +08:00
可以了解一下 DDD
|
69
git00ll 2022-05-26 23:14:25 +08:00
确实,我同事也有人喜欢整这些接口,每个 server 都整一个接口,我感觉没必要。
上面提单测的,单测与接口有什么关系,大部分情况下没接口使用 mockito 或 spock 都能搞定,遇到一点点搞不定的再整接口也行啊 |
70
RedBeanIce 2022-05-26 23:26:28 +08:00
还是网上流传的那句话,网友本科生 5%? v2exer 写业务的 5%?
|
71
ychost 2022-05-26 23:31:09 +08:00
当你写 framework 的时候,接口就很重要了,还有 IOC 、SPI 都非常方便
|
72
RiceNoodle 2022-05-27 00:57:29 +08:00
事实是,面向接口编程对写单元测试非常友好。
优秀的项目愿意这么设计是因为用得着,不代表每个项目都这么优秀。 |
73
asanelder OP |
74
xuanbg 2022-05-27 02:42:06 +08:00
别问,问就是规范和习惯。
虽然没啥用,而且 Java 也早就支持接口的默认实现,但大家还是这么写而不是写成默认实现。 |
75
Kontinue 2022-05-27 08:42:50 +08:00
有好处也有包袱
|
76
cherryas 2022-05-27 09:01:35 +08:00
因为写个 interface 没几分钟,写完还能自动生成 impl 。
|
77
micean 2022-05-27 09:46:43 +08:00
写 framework 、library 是一定要的,业务上很多就多余。别提 mock……
|
78
Narcissu5 2022-05-27 09:58:21 +08:00
- 有些地方需要接口,比如 java 动态代理
- 如果你的接口几乎都只有一种实现,那么你的抽象可能不够。实际上你没有用到 OO 最重要的能力也就是多态 - 如果你对多态不感兴趣,建议转 Go 。实际上 Go 更符合大多国内程序员的思维模式 |
79
wangxin13g 2022-05-27 10:06:44 +08:00
吐槽接口的写代码不写单元测试吗
写项目的时候就不考虑后期有人重构的吗 写项目就一个人吗? |
80
Akagi201 2022-05-27 10:13:59 +08:00
其实面向 interface 没有问题, 主要是要程序员要理解什么是 interface, 为什么会有 interface, 有的低级开发复制粘贴惯了, 直接把实现都复制过来这样根本没有意义. interface 本来就是让你自己梳理你的模块的接口的, 让功能自洽, 合理的设计接口, 而现实有的低级开发只是把一堆乱七八糟的东西堆到 interface.
|
81
qiumaoyuan 2022-05-27 10:48:17 +08:00
这个问题说到底是预先设计 v.s 重构的问题。很多人所谓的“重构”其实是重写,没办法重构只好预先设计出接口。
|
82
zzzkkk 2022-05-27 11:48:38 +08:00
通用性
可扩展 对小型项目 来说都是垃圾 过度设计是万恶之源 |
83
2NUT 2022-05-27 13:07:34 +08:00
我觉得是非常好的 编程习惯, 从整个项目的视角
|
84
Akagi201 2022-05-27 14:00:07 +08:00
有人说换种实现可以不换 interface 的, 可是有的低级开发设计 interface 时候就没考虑换个实现的兼容性考虑. 还是得一起重构. 而且除了库, 业务服务往往只会用到一种实现.不会存在两种实现共存的情况
|
85
VictorJing94 2022-05-27 14:15:08 +08:00
好像这个是某些教程里的..刚从 java 转出来时候还很不适应
|
86
chanchan 2022-05-27 18:00:00 +08:00
有的时候有用,写了的话也增加不了多少成本,有 ide,所以...
|
87
magiclz233 2022-05-28 02:07:33 +08:00
你要看啥情况,如果是一个大项目,很多人合作的公司项目,那这样搞,最简单的就是有一个规章,扩展性也更强。
要是你自己练手的项目,interface 不说了,你直接接口里面调 sql 都无所谓,自己开心就行 |
88
kongg 2022-05-28 11:03:57 +08:00
这个问题平时感觉很正常,你一说,我竟然也想了 这是为什么?
|
89
changz 2022-05-28 13:01:00 +08:00
你们不写单元测试的咩。。。
|