Porson's Bolg

Go语言关于Interface的理解与思考

因为缺乏接口编程经验,所以一直对Interface理解有些困惑,觉得既然我继承来之后也要全部实现,那么为什么不直接自己定义这些方法?而且也不理解为什么说go语言的Interface设计是颠覆性的。
刚才静下心来好好研究了一下接口以及实现案例,终于豁然开朗。

什么是接口(Interface)

其实说白了,接口就是类与类之间的一种协议,统一一个标准。你要调用我,那你就必须实现我的这些方法。我不需要知道你是怎么实现的,但是你一定要实现。甚至在Objec-C当中都不叫interface,直接protocol。

关于接口,知呼上有一个人是这么说的

接口就是个招牌。

比如说你今年放假出去杭州旅游,玩了一上午,你也有点饿了,突然看到前面有个店子,上面挂着KFC,然后你就知道今天中饭有着落了。

KFC就是接口,我们看到了这个接口,就知道这个店会卖炸鸡腿(实现接口)。

那么为神马我们要去定义一个接口涅,这个店可以直接卖炸鸡腿啊(直接写实现方法),是的,这个店可以直接卖炸鸡腿,但没有挂KFC的招牌,我们就不能直接简单粗暴的冲进去叫服务员给两个炸鸡腿了。

要么,我们就要进去问,你这里卖不卖炸鸡腿啊,卖不卖汉堡啊,卖不卖圣代啊(这就是反射)。很显然,这样一家家的问实在是非常麻烦(反射性能很差)。
要么,我们就要记住,中山路108号卖炸鸡,黄山路45号卖炸鸡(硬编码),很显然这样我们要记住的很多很多东西(代码量剧增),而且,如果有新的店卖炸鸡腿,我们也不可能知道(不利于扩展)。

作者:Ivony链接

到底有什么用?

我相信不少刚接触interface的人会跟我有一样的疑惑,我实现接口跟不实现接口没什么区别啊?反正都要实现这些方法。

问题的误区就在于,接口的使用并不是单人开发模式的。

刚才那个知呼答案下面的一个不是特别高票的答案我感觉更能解释这个问题。

你写接口你写实现,就不用写接口了。
我写接口你实现,接口不就用上了。我不给你规定好了,你怎么知道该实现哪些内容呢。
更进一步,我写接口你实现,你今天不在,我明天出差,程序后天交工,那我今天必须把调用这个接口的代码写好。所以就需要接口中有函数,有明确的函数签名。我写个接口,再把调用函数写好,明天你把接口实现了,传个实例进来,交工。
interface换个叫法就是contract,有点合同的意思。A实现了这个接口,代表A承诺能做某些事情。
B需要一些能做某些事情的东西,于是B要求,必须实现了A接口,才能被我调用。实际上也就是个“规范”。

作者:nonesuccess链接

用Go的文法举个例子,排序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package main
import (
"fmt"
)
type Sorter interface {
Len() int
Less(i, j int) bool
Swap(i, j int)
}
type Xi []int
type Xs []string
func (p Xi) Len() int { return len(p) }
func (p Xi) Less(i int, j int) bool { return p[j] < p[i] }
func (p Xi) Swap(i int, j int) { p[i], p[j] = p[j], p[i] }
func (p Xs) Len() int { return len(p) }
func (p Xs) Less(i int, j int) bool { return p[j] < p[i] }
func (p Xs) Swap(i int, j int) { p[i], p[j] = p[j], p[i] }
func Sort(x Sorter) {
for i := 0; i < x.Len()-1; i++ {
for j := i + 1; j < x.Len(); j++ {
if x.Less(i, j) {
x.Swap(i, j)
}
}
}
}
func main() {
ints := Xi{44, 67, 3, 17, 89, 10, 73, 9, 14, 8}
strings := Xs{"nut", "ape", "elephant", "zoo", "go"}
Sort(ints)
fmt.Printf("%v\n", ints)
Sort(strings)
fmt.Printf("%v\n", strings)
}

这样看,是不是就理解接口的意义了。

Go语言接口为什么是颠覆性的?

在其他编程语言当中,都是谁提供服务,谁提供接口。你需要调用我的服务,就必须声明你实现了我的接口。

翻译成人话就是我的逻辑力调用了一堆不同功能的函数组织,然后通过一些特定逻辑完成了某个功能,别的模块想要调用我这个功能,就必须把我这个功能里使用的这些函数都给实现了。

而这在逻辑上实际是说不通的,服务提供者怎么会确切的知道服务使用者的具体需求呢?当需求发生变化的时候,服务提供者就需要考虑使用者的需求,从而设计接口。而从理论上来说,每一个服务的开发人员都应该专注于自己的服务。

而go语言不同。go语言的接口是非侵入式接口,只要调用者本身实现了该接口的全部方法,就默认实现了该接口(事实上也确实是实现了这个接口),而不需要显示的声明实现某个接口。这极大的方便了接口的调用,开发人员不必再需要苦想接口的粒度,只需要专注功能函数的实现就可以了。