用Golang理解几种设计模式

用Golang理解几种设计模式

大部分模式都有一个共同点,那就是通过接口连接生产者和消费者。接口的抽象是关键,它反映了对底层类型的深刻理解。知道这一点可以简化事情,无论我们处理的是什么场景,或者使用的是什么语言。

至于为什么现在有这些模式,还有多少尚未被发现,以及背后的数学本质是什么,我也还无法回答。

创建型 - 实例如何创建 #

工厂 #

工厂方法负责创建一系列实现同一接口的实例。返回类型是接口而不是具体类。

 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}