golang的继承和多态

1. interface

interface struct 能否相互嵌套

  1. struct struct //继承(不能多态), 如果内部struct实现了接口, 它也相当于实现了接口
  2. struct interface //可以内部用interface多态
  3. interface interface //单纯的导入
  4. interface struct //不允许

interface实现多态

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
package main

import "fmt"

type P interface {
Say()
}
type P1 struct{}
type P2 struct{}

func (p *P1) Say() {
fmt.Println("say p1")
}
func (p *P2) Say() {
fmt.Println("say p2")
}

func main() {
p1 := &P1{}
p2 := &P2{}

var p P
p = p1
p.Say() // say p1
p = p2
p.Say() // say p2
}

组合继承并不会多态

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
package main

import "fmt"

type A struct {
}

func (a *A) ShowA() {
fmt.Println("showA")
a.ShowB()
}
func (a *A) ShowB() {
fmt.Println("showB")
}

type B struct {
A
}

func (b *B) ShowB() {
fmt.Println("b showB")
}

func main() {
b := B{}
b.ShowA()
}

// showA
// showB

2. struct

struct方法参数定义指针还是值

无论方法参数定义成指针还是值, 都可以调用

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
package main

import "fmt"

type S struct {
age int
}

func (s S) Value() {
fmt.Println(s.age)
}

func (s *S) Point(age int) {
s.age = age
}

func main() {

// 自己是指针, 能够调用一切
s := new(S)
s.Point(1)
s.Value() //1
fmt.Println(s) //&{1}

// 自己不是指针,也能调用指针函数修改值
v := S{}
v.Point(2)
v.Value() //2
fmt.Println(v) //{2}
}

3. 提问问题

golang 的继承实现,可以理解设计模式的策略模式吗?

不是一回事,结构体嵌入是静态,策略是动态的,策略模式更像golang的接口。

Go 的结构体嵌入(常被比作继承)和策略模式是两个不同目的的设计。前者为了组合与复用(静态),后者为了行为替换(动态)。

而 Go 通过持有接口字段的方式,则完美实现了“动态的、真正的策略模式”,这才是 Go 语言中实现行为可替换、高内聚低耦合的惯用手法(idiomatic way)。

特性结构体嵌入 (Go “继承”)策略模式 (Go 接口实现)
核心目的代码复用和组合。构建更复杂的对象。行为替换和解耦。让算法可以独立变化。
关系“is-a-like” 或 “has-a”。Dog 拥有 Animal 的所有特性。“delegates-to” 或 “uses-a”。Order 使用一个支付策略来完成工作。
灵活性静态的,在编译时就确定了。Dog 内部嵌入的是 Animal 类型,这是固定的,运行时无法将它换成 Cat动态的,在运行时可以改变。Orderstrategy 字段可以随时指向不同的支付策略实例。
本质一种结构性的设计。关注“对象由什么组成”。一种行为性的设计。关注“对象如何行动”。