go 无数据抽象设计

interface是golang的抽象设计的根基,是方法集合的接口,是一个非常强大的并且规范的指针,可以引用任意实现了该接口的方法集合的struct,不能定义属性,意味着在抽象设计里是不允许有数据的,使语言的编译运行管理更纯粹方便。

一切属性都是setter/getter

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
package main
type Surface struct{
skin string
}
func (s *Surface) Skin() string{
return "My skin is " + s.skin
}
type Men interface {
GetSurface() Surface
}
type European struct {
surface Surface
}
func (p *European) GetSurface() Surface{
return p.surface
}
type African struct {
surface Surface
}
func (p *African) GetSurface() Surface{
return p.surface
}
func Introduce(men Men){
s := men.GetSurface()
println(s.Skin())
}
func main() {
var s Surface
s = Surface{"white"}
e := European{s}
Introduce(&e)
s = Surface{"black"}
a := African{s}
Introduce(&a)
}

上例中的多态,通过setter/getter变相完成了property在interface定义,用方法多态来实现属性多态。

父类方法A调用子类方法B

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
package main
type Men interface {
Age() int
}
type Parent struct {
Men //隐式
m Men //显式
}
func (p *Parent) Age() int{
return 80
}
func (p *Parent) Display1() {
println(p.Men.Age())
}
func (p *Parent) Display2() {
println(p.m.Age())
}
type Child struct {
Parent
}
func (c *Child) Age() int{
return 40
}
func main() {
var child *Child
var parent *Parent
parent = &Parent{parent, nil}
child = &Child{Parent: *parent}
println("====parent")
child.Display1()
parent = &Parent{child, nil}
child = &Child{Parent: *parent}
println("====child")
child.Display1()
child.m = parent
println("====parent")
child.Display2()
child.m = child
println("====child")
child.Display2()
}

上例中的实现了在父类的A方法中调用父类或者子类的B方法,类似于抽象方法。因为go是静态语言,没有动态语言强大的查找机制,也没有虚函数(virtural method)和抽象方法(abstract method)之类的辅助高级别的多态。

幸好,golang有指针,即interface,又名接口,通过在父类定义接口类型的属性,并在实例化的时候动态绑定该属性的真正类型,来完成父类方法中一些多态方法的灵活调用,增加了公共部分的复用性。