golang的多态实现

多态(polymorphism)

多态是接口的一个关键功能和Go语言的一个重要特性。

当非接口类型T的一个值t被包裹在接口类型I的一个接口值i中,通过i调用接口类型I指定的一个方法时,事实上为非接口类型T声明的对应方法将通过非接口值t被调用。 换句话说,调用一个接口值的方法实际上将调用此接口值的动态值的对应方法。 比如,当方法i.m被调用时,其实被调用的是方法t.m。 一个接口值可以通过包裹不同动态类型的动态值来表现出各种不同的行为,这称为多态。

当方法i.m被调用时,i存储的实现关系信息的方法表中的方法t.m将被找到并被调用。 此方法表是一个切片,所以此寻找过程只不过是一个切片元素访问操作,不会消耗很多时间。

注意,在nil接口值上调用方法将产生一个恐慌,因为没有具体的方法可被调用。

一个例子:

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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
package main

import "fmt"

type Filter interface {
About() string
Process([]int) []int
}

// UniqueFilter用来删除重复的数字。
type UniqueFilter struct{}
func (UniqueFilter) About() string {
return "删除重复的数字"
}
func (UniqueFilter) Process(inputs []int) []int {
outs := make([]int, 0, len(inputs))
pusheds := make(map[int]bool)
for _, n := range inputs {
if !pusheds[n] {
pusheds[n] = true
outs = append(outs, n)
}
}
return outs
}

// MultipleFilter用来只保留某个整数的倍数数字。
type MultipleFilter int
func (mf MultipleFilter) About() string {
return fmt.Sprintf("保留%v的倍数", mf)
}
func (mf MultipleFilter) Process(inputs []int) []int {
var outs = make([]int, 0, len(inputs))
for _, n := range inputs {
if n % int(mf) == 0 {
outs = append(outs, n)
}
}
return outs
}

// 在多态特性的帮助下,只需要一个filteAndPrint函数。
func filteAndPrint(fltr Filter, unfiltered []int) []int {
// 在fltr参数上调用方法其实是调用fltr的动态值的方法。
filtered := fltr.Process(unfiltered)
fmt.Println(fltr.About() + ":\n\t", filtered)
return filtered
}

func main() {
numbers := []int{12, 7, 21, 12, 12, 26, 25, 21, 30}
fmt.Println("过滤之前:\n\t", numbers)

// 三个非接口值被包裹在一个Filter切片的三个接口元素中。
filters := []Filter{
UniqueFilter{},
MultipleFilter(2),
MultipleFilter(3),
}

// 每个切片元素将被赋值给类型为Filter的循环变量fltr。
// 每个元素中的动态值也将被同时复制并被包裹在循环变量fltr中。
for _, fltr := range filters {
numbers = filteAndPrint(fltr, numbers)
}
}

输出结果:

1
2
3
4
5
6
7
8
过滤之前:
[12 7 21 12 12 26 25 21 30]
删除重复的数字:
[12 7 21 26 25 30]
保留2的倍数:
[12 26 30]
保留3的倍数:
[12 30]

在上面这个例子中,多态使得我们不必为每个过滤器类型写一个单独的filteAndPrint函数。

除了上述这个好处,多态也使得一个代码包的开发者可以在此代码包中声明一个接口类型并声明一个拥有此接口类型参数的函数(或者方法),从而此代码包的一个用户可以在用户包中声明一个实现了此接口类型的用户类型,并且将此用户类型的值做为实参传递给此代码包中声明的函数(或者方法)的调用。 此代码包的开发者并不用关心一个用户类型具体是如何声明的,只要此用户类型满足此代码包中声明的接口类型规定的行为即可。

事实上,多态对于一个语言来说并非一个不可或缺的特性。我们可以通过其它途径来实现多态的作用。 但是,多态可以使得我们的代码更加简洁和优雅。


-------------The End-------------

本文标题:golang的多态实现

文章作者:cloud sjhan

发布时间:2019年03月18日 - 15:03

最后更新:2019年03月18日 - 16:03

原始链接:https://cloudsjhan.github.io/2019/03/18/golang的多态实现/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

cloud sjhan wechat
subscribe to my blog by scanning my public wechat account
坚持原创技术分享,您的支持将鼓励我继续创作!
0%
;