大部分模式都有一个共同点,那就是通过接口连接生产者和消费者。接口的抽象是关键,它反映了对底层类型的深刻理解。知道这一点可以简化事情,无论我们处理的是什么场景,或者使用的是什么语言。
至于为什么现在有这些模式,还有多少尚未被发现,以及背后的数学本质是什么,我也还无法回答。
创建型 - 实例如何创建 #
工厂 #
工厂方法负责创建一系列实现同一接口的实例。返回类型是接口而不是具体类。
1// type A, B, C all implement I
2type I interface {}
3
4func factory(string t) I {
5 switch t {
6 case "A":
7 return new A()
8 case "B":
9 return new B()
10 case "C":
11 return new C()
12 }
13}
单例 #
在应用程序生命周期中只有一个实例。
1type A struct{}
2
3var (
4 one *A
5 m = &sync.Mutex{}
6)
7
8func Get() {
9 // prevents unnecessary lock
10 if one == nil {
11 m.Lock()
12 defer m.Unlock()
13
14 // prevents unnecessary creation
15 if one == nil {
16 one = &A{}
17 return one
18 }
19 return one
20 }
21 return one
22}
原型 #
实例通过对一个母体克隆而不是实例化获得。它们的类实现了一个公共接口,该接口定义了一个克隆方法,因此返回类型是接口而不是具体类。
1type I interface {
2 clone() I
3}
4
5type A struct {}
6
7func (a *A) clone() I {
8 tmp := *a
9 return &tmp
10}
11
12func main() {
13 var a, a2 I
14 a = &A{}
15 a2 = a.clone()
16}
结构型 - 如何组织对象 #
桥接 #
类A将任务委托给类B。它们共享一个公共接口。
1type I interface {
2 do() string
3}
4
5type A struct {}
6func (a A) do() string {
7 return "hello"
8}
9
10type B struct {
11 i I
12}
13func (b B) do() {
14 return b.i.do()
15}
16
17func main() {
18 b:= B{
19 i: A{}
20 }
21
22 b.do() // => "hello"
23}
适配器 #
类A通过适配器与不兼容的类B进行交互。
1type A interface {
2 produce() int
3}
4
5type B interface {
6 consume(string s)
7}
8
9type AtoBAdapter struct {
10 A
11}
12
13func (a AtoBAdapter) produce() string {
14 return strconv.Itoa(a.A.produce())
15}
16
17func main() {
18 a := AtoBAdapter{
19 A: A{}
20 }
21 b := B{}
22
23 b.consume(a.produce())
24}
组合 #
如果业务模型是递归的,可以使用树形结构。
1type I interface {
2 do()
3}
4
5type Component struct {
6 children []I // can be component or node
7}
8
9func (c Component) do() {
10 for _, child := range r.children {
11 child.do()
12 }
13}
14
15type Node struct {}
16
17func (n Node) do() {}
18
19func main() {
20 c := Component{
21 children: []I{
22 Component{},
23 Node{},
24 }
25 }
26}
立面 #
为单一入口定义了新接口。在其后,是一个涉及许多类的复杂子系统,但新的立面(控制面板)掩盖了背后的细节。
1// the only interface for user interaction
2type I interface {
3 foo()
4 bar()
5}
6
7type A interface {
8 a1()
9 a2()
10}
11
12type B interface {
13 b1()
14}
15
16type system struct {
17 A
18 B
19}
20func (s system) foo() {
21 s.A.a1()
22 s.B.b1()
23}
24func (s system) bar() {
25 s.A.a2()
26}
27
28func main() {
29 s I := system{
30 A: A{}
31 B: B{}
32 }
33
34 s.foo()
35 s.bar()
36}
行为型 - 如何产生变化 #
策略 #
上下文从多个实现了共同接口的类中选择一个实例。
1// type A, B, C all implement I
2type I interface {
3 do()
4}
5
6func main() {
7 var executor I
8
9 switch strategy {
10 case "A":
11 executor := new A()
12 case "B":
13 executor := new B()
14 case "C":
15 executor := new C()
16 }
17
18 executor.do()
19}
模板 #
A类是B C D类的模板,可以在定义时重写以产生变化(而不是在运行时)。
1type interface I {
2 foo()
3 bar()
4}
5
6// a default implementation of I
7type template struct {}
8func (t template) foo() {}
9func (t template) bar() {}
10
11// only overwrites foo
12type A struct {
13 template
14}
15func (a A) foo() {
16 fmt.Print("a foo")
17}
18func (a A) bar() {
19 a.template.bar()
20}
21
22// only overwrites bar
23type B struct {
24 template
25}
26func (b B) foo() {
27 b.template.foo()
28}
29func (b B) bar() {
30 fmt.Print("b bar")
31}
装饰 #
B装饰A以改变结果,但不改变A的原始行为。
1type I interface {
2 do()
3}
4
5type A struct {}
6
7func (a A) do() int {
8 return 1
9}
10
11type B struct {
12 i I
13}
14
15func (b B) do() int {
16 return b.i.do() + 1
17}
18
19func main() {
20 a := A{}
21 b := B{
22 i: a
23 }
24
25 a.do() // => 1
26 b.do() // => 2
27}