这个问题百度了很多一直也没看明白,百度上各种文章写的也不太清晰。
有没有通俗易懂白话,来讲讲到底有什么好处
例如
接口类型 变量 = new 实现类();
实现类类型 变量 = new 实现类();
1
MikeLei 2019-08-16 14:07:49 +08:00 1
多用于分层应用,多出一个胶水层,来隔离实现类,与业务逻辑类,业务逻辑类只需要依托于接口类.如果实现类变了,只需要跑到胶水层里面改变接口类的指向就可以了~
|
2
cheng6563 2019-08-16 14:08:34 +08:00 via iPhone 2
局部变量的话没什么区别,习惯而已。
但是方法参数或成员变量上用法就有区别了。 |
3
HuHui 2019-08-16 14:17:04 +08:00 via Android 2
依赖与实现分离
|
4
ipwx 2019-08-16 14:17:49 +08:00 via Android 1
因为 java 没有多重继承。用户需要继承自己的基类,所以你只能约定接口。
|
5
Takamine 2019-08-16 14:18:46 +08:00 2
面向接口编程。
|
6
love 2019-08-16 14:19:35 +08:00 1
java 的过度设计习惯,接口和实现分隔,哪怕你的软件只有一个实现
你用别的语言 python/php/js 写代码基本不会这么写,甚至类都很少用到 |
7
hhhsuan 2019-08-16 14:19:40 +08:00 via Android 3
多态
|
8
lhx2008 2019-08-16 14:21:32 +08:00 via Android 2
主要是面向接口编程,我这样写是说,我实现了这个接口的所有功能,但是接口外的功能,我不能做出保证,你也别调用。
面向接口编程的好处就是调用者只关心接口而非具体实现,具体实现可以更换也不受影响。 比如我要吹风机,我定义接口开,关,调节档位。只要是满足这些功能,我都照用。 现在有一个戴森吹风机,还有 XX 模式,但是,我不关心什么牌子的吹风机,我只关心他能不能开。这样我换吹风机也能适应。 至于 Service 层里面的接口设计,我个人认为是有一点形式化了,意义不大。 |
9
gz911122 2019-08-16 14:22:32 +08:00 1
java 的习惯性过度设计
早年中了设计模式的毒 |
10
linxl 2019-08-16 14:23:13 +08:00 1
多态. 实际项目中我几乎没这么用过, 一般就一个类改到底.
|
11
Wangjl OP 感觉还是好绕,没听懂呢。
|
12
JerryCha 2019-08-16 14:35:23 +08:00 2
大概比写成 Object instance = new XXXX()多一些约束,比 Father instance = new XXXX()多一些自由。
|
13
Wangjl OP |
14
micean 2019-08-16 14:37:39 +08:00 1
看实际场景
一般都没啥意义 现在都直接 var object = new Object() |
15
chendy 2019-08-16 14:38:41 +08:00 1
对于 new 这个场景其实无所谓,因为已经指明了实现类,用接口接意义不大
如果是方法返回值 / 方法参数 / 成员变量,最好用接口 |
16
yule111222 2019-08-16 14:39:25 +08:00 1
是你接口定义得太多了,普通的单表增删改查根本不需要定义接口
|
17
yule111222 2019-08-16 14:40:45 +08:00 1
依赖抽象不依赖具体,是设计原则中的东西,在 JAVA 中被滥用了
|
18
anzu 2019-08-16 14:53:12 +08:00 1
仅就接收变量这一点来说,实现类未必是自己写的,但约定的接口大家都知道,通过接口可以约束自己的代码遵照约定而不会意外使用了实现类的额外功能。
|
19
iiiiiiiiii 2019-08-16 14:54:50 +08:00 1
说下自己的见解:)
[[封装]] 如果实现类 extends 或 implement 功能繁杂(就是 private 方法与其他接口实现),那么 IDE 提示简明扼要. [[继承与多态(自己瞎想的)]] 一般我们都说去买菜,但是买什么菜得看各种情况你才能做出选择.把 new 实现类(); 抽成一个方法 getInstance(){if 来客人了 return 多买点好的(龙虾); else return 自己看想吃什么(青菜);}这种情况下显然使用接口类型要灵活的多,反正这个食物接口都是传给做菜的厨师. 在项目大的情况下,使用接口来集成各个组件间的关系比直接实现类优雅的多.你说要用实现类中独有的方法?那还是通过接口传参然后在代码块中自行 instanceof 和(Object)强转使用. |
20
rockyou12 2019-08-16 14:57:05 +08:00 2
不是写框架层面的,而是局部变量没必要这样写,浪费时间。即便需要修改类型,现代 ide 也能帮你分析并替换,没必要过度使用。
|
21
Caballarii 2019-08-16 14:57:12 +08:00 1
读一读 spring 就懂了
|
22
TobiahShaw 2019-08-16 15:05:11 +08:00 1
单实现类接口意义不大,多实现接口配合泛型或者其他特性很方便;另外这个接口定义和实现不是同一方做的;
|
23
janus77 2019-08-16 15:07:49 +08:00 1
给你一个场景:
父类定义变量:接口类 a 子类重写:a=实现类。 |
24
onice 2019-08-16 15:09:35 +08:00 1
方便代码重用。接口是对类功能的抽象,List<> list = new ArrayList<>()和 List<> list = new LinkedList<>(),他们的功能都是一样的,但是实现不一样。在实际开发中,例如 DAO 层,通过定义接口,可以写好几套实现。例如对于 mysql 的一套,对于 oracle 的一套。
|
25
qiyuey 2019-08-16 15:11:55 +08:00 1
new 对象时接收没必要用接口,因为 new 所在的方法肯定是强感知的,主要使用接口的是模板方法、工具类等,关注的是实现了接口的一类对象。
|
26
Wangjl OP new 对象时用其接口类型变量来接收,这么做的好处是
1.统一规范 例如:我定义了一个接口,里面有 a、b、c 三个方法 然后别人实现了该接口 如果我用 实现类 对象名 = new 实现类 这种方式 new 对象 此时如果实现类中还定义了 d 方法,就可以通过该对象调用 d 方法 如果此时是多人开发的场景,我们发现实现类 d 方法有问题。然后别人就重写了该实现类,例如删除或修改了 d 方法 此时调用 d 方法的地方,我们全部都需要删除或修改 而如果是用接口作为接收类型创建的对象: 本身该接口就是我们定义的,我们明确知道我这个功能只需要 a、b、c 这三个方法 这时候,你拿去实现。你实现类中还定义了一个 d 方法 但我 new 对象的时候,用接口来接收,这样我就不管你实现类里实现了什么特有方法,我都不关心 我用接口接收,这样就只能调用我接口中定义的 a、b、c 三个方法,这样以后你实现类再改变 我都不需要去改变我的对象的调用 这样做的好处就是,限定只能调用接口中的方法。 不知道我这么理解对不对。 |
27
fkdog 2019-08-16 15:18:59 +08:00 2
如果你有做过框架的话,你会体会到多态给你带来的好处。
在实际业务开发里,这种方式的编码带来的好处比较有限。 大部分其实也是大家约定俗成保留了这种方式。 |
28
cwjokaka 2019-08-16 15:19:03 +08:00 1
对某个对象,调用层知道的信息越少越好。最浅显的作用:实现类类型 变量 = new 实现类(); 至少改代码只需改 new 的那部分,而不用改类型🤪
|
29
Raymon111111 2019-08-16 15:20:46 +08:00 1
简单讲用的时候可以统一处理. 明白不了有什么好处是因为看的例子确实不好. 我这里举一个例子我遇到实际工程里的例子吧.
比如现在工程调用算法开发的类实现算法功能, 不同的功能有不同的算法. 有 A1 算法, A2 算法. 工程并不想知道算法的细节, 也不关心算法是哪来的, 最简单的方案是算法提供单一 API, 比如叫做 Algor.compute(input). 工程只要在 input 上约定想用某个算法, 这个内部自动就找到对应的算法. 那这里算法去真正实现 Algor.compute 的时候这个接口肯定是通用的, 类似下面这样的逻辑. Algor.compute() { A a = getAlgor(input); // 通过 input 拿到真正 A1 或者 A2 或者其它的算法 a.compute(); // 通用的算法实现接口, A1, A2 都去实现 A, 算法真正的实现写在 compute 里 } 那这个 A 就是 A1, A2 的接口类. 可以看到 Algor.compute 这个方法只用到 A 这个接口类. |
30
wysnylc 2019-08-16 15:21:16 +08:00 1
@fkdog #27 说得对,写业务是用不太到接口的,框架和工具会比较多使用接口的多实现来实现功能实现的替换(有点绕哈哈
|
31
otakustay 2019-08-16 15:26:58 +08:00 1
让后面用这个对象的人别瞎 JB 乱用,方便以后在符合左边接口的前提下改了实际右边的类型后不会一片错
|
33
pisc 2019-08-16 15:45:16 +08:00 via Android
我来唱反调好了,大部分情况下没用,楼上张嘴闭嘴多态,用实现类接收就不能用多态了?你们懂个毛的 polymorphism,这种滥用 subtyping polymorphism 除了会丢失类型精度,还有什么意义?根本上和静态类型的动机是相违背的
|
34
doneself 2019-08-16 15:46:05 +08:00
有几个用处,一来某人定义了接口规范,后面其他人实现类的功能,就能保证他的方法名一致。
还有就是多态更规范一点。例如我定义一个 ExcelHelper 的工具类。删除一个单元格在 97 跟 2003、2007 版本实现可能都不一样。 那么就可以 定义一个接口 IExcelHelper,定义一个 DeleteCell()的方法。 调用者就不用考虑每次都用哪个实现类。初始化的时候,直接。 IExcelHelper Helper = new Helper97(); 或者 IExcelHelper Helper = new Helper03(); 再或者 IExcelHelper Helper = new Helper07(); 调用者就不用关心实现,无论是 97,03,07 调用都是 IExcelHeler.DeteleCell()。 反正就是 规范 、 分离的原则。 |
35
xiangyuecn 2019-08-16 15:46:42 +08:00
在真真实实需要用到接口的地方,硬是不用接口,那么只能用反射。不像弱类型语言,随便给个对象,.xxx()随便调,只要你定义了 xxx😒 不单是 java,其他有接口的语言都是这个样子吧。
|
36
pisc 2019-08-16 15:51:47 +08:00 via Android
还有什么类型变动不用改类型什么的,最简单的做法你可以连左边的类型都不用写,直接用 var,让编译器给你推导出类型就 OK 了
|
37
AsiaToyo 2019-08-16 15:55:14 +08:00
父類引用指向子類對象
|
38
vincel 2019-08-16 16:00:35 +08:00
接口的意义是松耦合,通俗一点来讲就是:"不管接口的实现类怎么改,只要你实现了这个接口,我就可以调用你,屏蔽掉其他所有不必要因素。"
举个例子:假如你负责的模块 A 要处理数据,而具体处理方法是另一个小组模块 B 实现的,他们提供给你的类叫 MyTask,用 getTask 方法返回给你。所以你的代码是: Runnable r = ModuleB.getTask(); //你的模块有一万个方法要用到这个对象 functionA(Runnable r) functionB(Runnable r) .... 以后不管他的实现类怎么改怎么换,只要他实现了 runnable 接口,你都不用管。但如果你是用 MyTask 声明的对象,那么只要他们以后把实现类换成 TaskB 了或者换改类名了,那么你那一万处代码全部要改。 |
39
MaxTan 2019-08-16 16:09:34 +08:00 2
光你给出的例子那种写法没啥卵用;
但同一接口有多实现或者做类型约束类似场景,接口就非常有用;其实接口就是为了实现面向对象里面的多态性 大白话就是电脑有 usb 插口(声明一个 usb 接口类型),不管你插入的设备(对象)是鼠标还是键盘,只要它们带 usb 头(实现 USB 接口)就行了,好处就是光一个 usb 接口可以插 u 盘、鼠标、手柄、音响.... 其他电脑配件同理,只要有接口标准,配置一切皆可选。 这就是多态装机 |
40
tedcon 2019-08-16 16:20:34 +08:00
依赖倒转原则看一下
|
41
kkkkkrua 2019-08-16 16:41:49 +08:00
私有变量没啥用
|
42
Vtwoguest 2019-08-16 17:24:25 +08:00
很类似于职场的中庸之道 就是什么事情都模模糊糊
例如: 你工资多少? 不太多 也就那样 你感觉谁漂亮? 都还行 我看不出来 你觉得那个人怎么样? 还行 |
43
stevenkang 2019-08-16 17:30:58 +08:00
====== 抽象类 ======
C2 可以开自动挡,C1 不仅可以开自动挡。这时候我们理解为 C2 或者 C2 以及以上的,均可以开自动挡,这就是抽象类(不用管你是 C1 还是 C2,只要是 C2 以及以上,均可以调用开自动挡) ====== 接口 ====== C2 和 C1 都是驾照(实现了驾照接口),然后有驾照都可以开车,于是: 驾照 jz1 = new C1 () 驾照 jz2 = new C2 () jz1.可以开车() jz2.可以开车() ====== 总结 ====== 有了抽象类和接口的概念,对于交警(使用者)来说,不用管你具体实现是考的 C1 还是 C2,是不是很方便? |
44
CEBBCAT 2019-08-16 17:34:08 +08:00 via Android
你要是存到实现类里,那你搞接口可不就是脱裤子放屁吗?
|
45
tabris17 2019-08-16 17:36:30 +08:00 1
为了实现多态
|
46
luozic 2019-08-16 17:44:34 +08:00 via iPhone
解耦合,并且有助于封装子功能模块。
|
47
npe 2019-08-16 17:52:11 +08:00
约定俗成,面向接口开发。
|
48
cs419 2019-08-16 17:52:52 +08:00
接口是在可变时, 意义大
之后没有多态化,那只能看成是种仪式感 fun getCar(){ // 比如此时 car 可变 Car car = null; if(...) car = new CarA(); if(...) car = new CarB(); if(...) car = new CarC(); return car; } // 如果 是某个方法的返回值 则 car 是多态 Car car = getCar(); // 如果作为参数传给方法 Call(Car c)时 也能达到多态的目的 而 Call(CarA c) 显然是不行的 回头谈楼主的示例 那可以说更多是仪式感 Car car = new Car(); car.run(); |
49
passerbytiny 2019-08-16 17:58:15 +08:00 1
首先排除以下情形:类似于 Service、ServiceImpl 这种,接口-实现一一对应的定义,此时将变量类型定义为接口而不是实现类纯粹是一种约定。
上述情形被批判的程度,仅次于贫血领域模型,二者都属于拍脑袋设计+回到过程编程的返祖设计,连过度设计都算不上。 至于用“接口类型”而不是“实现类类型”定义变量的原因,不是因为有好处,而是因为你要的就是一个“接口类型”的变量。如果你明确的要一个“实现类类型”的变量,那你就该定义成“实现类类型”变量。但通常你想要的只是一个接口的实例而不是类的实例,那么你就应该精确的定义成“接口类型”变量。 举例来说:如果你想要一个“列表”,那么就要“ List a = new ArrayList()”或者“ List a = new LinkedList()”;如果你非常精确的想要一个“数组列表”,那么就要“ ArrayList a = new ArrayList()”。 另外,接口类型 /基类 变量 = new 实现类 /子类(); 这种形式,是多态的一个点。前几楼那些认为过度设计的真是暴漏智商了,“多态”这个面向对象基本特性都不知道。 |
50
HangoX 2019-08-16 18:24:29 +08:00
最少依赖原则啊,我只要接口的内容就够了,不需要其他内容,就用接口即可,当替换实现的时候就不蛋疼了
|
51
Sasasu 2019-08-16 21:10:01 +08:00 via Android
为了让软件运行缓慢,方便优化。
接口隐藏了实际算法的复杂度,继续用楼上的例子,linked list 和 array list。 Java 的 linked list 支持随机访问,一个返回 list 实际上是 linked list 的接口会埋下产生巨大复杂度的隐患。这样日报里就可以写 “经过一天的排查,修复了一个运行缓慢的算法,压测性能提升 60%”。 ServletRequest 到现在也只有一个 HttpServletRequest 还一般是阻塞的。 JDBC 只规定了同步接口,导致整个 Java 的异步生态被锁死在线程池写数据库里。 还有人记得 javax 里面的一堆接口么? |
52
iPhoneXI 2019-08-16 22:05:33 +08:00 via Android
毕竟喜欢 Python,Golang 的接口设计
Python 是鸭子类型, |
54
wenmingvs 2019-08-16 23:39:36 +08:00 via iPhone
设计模式六大原则之一,依赖倒置
|
55
hantsy 2019-08-16 23:51:35 +08:00
不是应该这样写吗,var list=List.of(1,2,3)
|
56
lhx2008 2019-08-17 00:17:16 +08:00 via Android
@passerbytiny ServiceImpl 有没有可能是当初 IOC 的锅?其实现在完全没有必要这样设计了。
|
57
francis59 2019-08-17 01:15:17 +08:00
依赖于接口相当于服务使用方和提供方的一种约定,只使用约定好的接口里的方法,这样更换服务提供方就不那么蛋疼了,而如果依赖于具体实现,想想要是每种服务提供方的方法(方法名、参数、返回值等等)都不一样,或者用了某种实现独有的方法,那更换实现就真蛋疼了
|
58
nguoidiqua 2019-08-17 01:29:01 +08:00 via Android
原因很简单,一些不同的类有同样的方法,但方法效果不同。
我现在要把这一堆不同的类当作参数丢到某个方法里面去调用这个方法。 赋值给接口的话,你就不用去做区分处理了,这个和赋给父类差不多。 |
59
billlee 2019-08-17 01:41:07 +08:00
局部变量的话,没有卵用。新一点的 kotlin/scala 都可以自动推导了。
|
60
20015jjw 2019-08-17 07:09:36 +08:00
好恐怖回国要是面试上面的乱七八糟术语都看不懂- -
|
61
xuanbg 2019-08-17 08:49:46 +08:00
1、我只需和你约定接口有哪些方法,分别是什么参数,你就可以在我没有提供实现的情况下愉快的写代码了,不必等我写完逻辑再开始。
2、同一个接口可以在不同的情况下使用不同的实现,这样,你只需在构造的时候传一个正确的实现类就行,下面的逻辑都是一样的,就不用写长长的 if/else。 |
62
arthas2234 2019-08-17 10:04:10 +08:00
最直白的:多态,解耦
去看下 Java 关于容器的实现,你会有一个清晰的认识 |
63
macemers 2019-08-17 10:04:43 +08:00
我的意见是,首先,放弃使用百度,排除一下困难直接使用 google。其次,放弃使用中文术语,尽量使用英文术语。养成这样的习惯,之后学习编程才比较容易
这样的问题你可以 google 例如 why interface is over/better than concrete object/implemetation in Java |
65
hanxiaomeng 2019-08-17 11:34:59 +08:00
假定有如下方法:
``` public static void test(Animal a) { a.print(); } public static void test2(Cat c) { c.print(); } ``` 现在有一个 Cat 类: ``` test(new Cat()); test2(new Cat()); ``` 某一天我添加了 Dog: ``` test(new Dog()); //test2(new Dog()); ``` |
66
hanxiaomeng 2019-08-17 11:39:10 +08:00
@hanxiaomeng 接口的存在就是为了实现更强大的多态,提高程序的可扩展性。理解多态,理解可扩展性,自然就理解接口了。
|
67
pisc 2019-08-17 11:54:29 +08:00 via Android
@vincel 大哥,是你无知还是我无知你不会查一查吗?你这样很尴尬啊,我都不知怎么回你了,var 是 Java10 的 feature 好吗?
|
68
aguesuka 2019-08-17 11:57:49 +08:00 via Android
因为 java 代码自带文档,按下点的一瞬间,你能调那些方法 idea 已经帮你算好了
|
70
nicevar 2019-08-17 12:15:17 +08:00
很多人说的太抽象了不容易理解,这个问题从实际应用上来说明比较好看懂,举个例子,比如你的软件要对接不同的广告系统,百度、腾讯、阿里的等,你在你的项目里面 new 不同的广告对象把所有的广告 sdk 搅在一块不是特别蠢么?所以你只需要在自己的项目中增加一个广告模块,抽象好共同特征的接口,这样无论他们的 sdk 怎么变动,你的项目无需修改,只需要动一下对接各个 sdk 的实现就行了,而且发布不同的版本也非常方便。
|
71
Sasasu 2019-08-17 13:21:59 +08:00
> 比如你的软件要对接不同的广告系统,百度、腾讯、阿里的等
不同的广告系统支持的功能是不同的,没干过广告,拿推送举例。 Apple 不允许系统的得知这个设备 UUID 是不是失效了,用户有没有卸载程序,只能推送文字并发出特定声音。 Android 允许系统探测用户有没有卸载程序,推送可以多行 带图,并能发出特定声音。 Android 又有好几家推送的 vendor, 支持的特点也不相同,技术特性比如 webp 支持,业务特性比如 PNG 转成 jpg 时透明背景是白色还是黑色,还是能根据手机的主题转换。 如果你有一个 interface 那么你只能在所有的推送系统中取子集,Android 系统的推送只有一行文字。 请做个实验,看看两种推送那种打开率高,再考虑你要不要把所有推送抽象成 interface,还是让运营明白她发出去的推送在不同手机上展示的效果究竟是什么样子的。 你要卖一个推送产品,那种卖的更好? |
72
Sasasu 2019-08-17 13:29:10 +08:00
可能这个推送 SDK 支持最好的平台是 BB 机,但是 BB 能组播,智能机不能组播。大概是个不能组播的 BB 机推送 SDK
|
73
nicevar 2019-08-17 13:53:50 +08:00
@Sasasu 你没看明白意思,我说的对接广告系统是指客户端展示,无论你是哪一家的广告 SDK,做的功能无非就是开屏广告、浮层、banner、native 这些广告展示方式,因此只需要抽象这些共同点做成统一接口就行了。
|
74
Sasasu 2019-08-17 16:10:52 +08:00 via Android
于是你的广告 sdk 只支持 “开屏广告、浮层、banner、native ” 并且广告的渲染层和业务的渲染层解耦,导致广告出来的总比业务慢半秒,还经常挡住业务按钮
|
75
Sasasu 2019-08-17 20:56:56 +08:00
https://www.v2ex.com/t/588729#reply7
> 收到非 200 抛异常,按照返回码注册处理函数,发不出带 body 的 get,发不出带 urlencode 的 post put,multipart/form-data 不能带字符串甚至只能放文件,把数组用任何方式序列化在 urlencode 里,不跟随 302,不关心 connection close 的 HTTP client 都应该去死 这就是 Java 的 interface 带来的间接影响 |
76
nnnToTnnn 2019-08-18 01:32:40 +08:00
当你这样写代码的时候,就没啥吊意义了
接口类型 变量 = new 实现类(); 实现类类型 变量 = new 实现类(); 如果在没有 ioc 框架的情况下 () => (className){ Class clazz = Class.forName(className); 接口类型 变量 = constructor.newInstance(); } 或者直接用 ioc 框架,例如 spring 接口的目的是为了隔离与实现类的关系,这下好了,都是强依赖了。 主要是为了后期动态切换实现类,而不用过多的修改项目结构 |
77
nnnToTnnn 2019-08-18 01:37:09 +08:00
@vincel var 只是一个特性,Java 无论在那个版本 var 都是一个保留关键字。 你这样说估计可能太了解 Java
|
78
nnnToTnnn 2019-08-18 01:43:32 +08:00
其次所谓的接口,抽象类等等,都没有屌用。没有这些东西一样能开发出一个健壮的系统。
当你去写代码的时候,可以思考下,这个我为什么要用这个设计模式,可以为我带来什么优点,以及缺点是否可以忍受。 团队接受水平 and 项目复杂程度 and 自己理解 不要为了设计模式而去设计模式。 比如很简单的一个例子 例如 ``` 接口类型 变量 = new 实现类(); 实现类类型 变量 = new 实现类(); ``` > 如果这个实现类,并不重要,且以后不会有多大的变化,是否用接口进行动态其实意义并不大 ``` 实现类 变量 = new 实现类(); 实现类 变量 = new 子实现类(); ``` 一样可以用继承的方式进行强制转换。 |
79
ccxml 2019-09-24 15:22:27 +08:00
看着舒服,一个几千行的 class 只需要看他的接口就能知道个大概,省事
|
80
ccxml 2019-09-24 15:23:46 +08:00
特别是维护旧代码的时候,有接口没接口区别老大了
|