再次通过创建型模式视角回顾Go
形而上 Lv5

创建型模式主要目标是提供一种灵活方式创建对象,同事隐藏创建的具体细节,降低代码耦合度,提高复用性和可维护性。

创建型模式-单例

单例模式,Singleton, 确保只有一实例,并提供全局访问点。

使用场景:配置管理,日志记录, 数据库连接池等。

global.DB, global.Config 并不是单例模式,而是直接使用全局变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package database

import "sync"

type DB struct {
}

var db *DB

var once sync.Once

func initDB(dsn string) *DB {
return &DB{}
}

func GetDB() *DB {
once.Do(func() {
db = initDB("xxx")
})
return db
}

单测:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package database

import (
"fmt"
"testing"
)

func TestGetDB(t *testing.T) {
db1 := GetDB()
db2 := GetDB()
db3 := GetDB()

fmt.Printf("%p\n", db1)
fmt.Printf("%p\n", db2)
fmt.Printf("%p\n", db3)
}

创建型模式-简单工厂模式

目标是将对象的创建和使用分离,解耦合

简单工厂模式:一个工厂类负责创建所有产品,通过条件判断来决定创建哪种产品。

简单工厂并不是正式的设计模式,而是一种编程习惯。(所以有23种设计模式,和24种设计模式两种说法)

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

type Pay interface {
PayPage(price int64) (string, error)
}

type AliPay struct{}

func (p *AliPay) PayPage(price int64) (string, error) {
return "aliPay", nil
}

type WexinPay struct{}

func (p *WexinPay) PayPage(price int64) (string, error) {
return "wexinPay", nil
}

type PayType int8

const (
AliPayType = 1
WexinPayType = 2
)

func NewPayPage(payType PayType) Pay {
switch payType {
case AliPayType:
return &AliPay{}
case WexinPayType:
return &WexinPay{}
}
return nil
}

单测:

1
2
3
4
5
6
7
8
9
10
11
12
13
package factory_pay

import (
"fmt"
"testing"
)

func TestNewPayPage(t *testing.T) {
page, _ := NewPayPage(WexinPayType).PayPage(1)
payPage, _ := NewPayPage(AliPayType).PayPage(1)
fmt.Println(page)
fmt.Println(payPage)
}

创建型模式-工厂方法模式

工厂方法模式定义了一个创建对象接口,单具体的创建逻辑延迟到了子类种,每一个子类负责创建一种具体的产品

特点:每个产品对应一个工厂类,符合开闭原则,新增产品只需要增加新的工厂类,无需修改现有代码。

使用场景:产品种类较多,且创建逻辑复杂的场景。

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

type Pay interface {
PayPage(price int64) (string, error)
}

type AliPay struct{}

func (p *AliPay) PayPage(price int64) (string, error) {
return "aliPay", nil
}

type WexinPay struct{}

func (p *WexinPay) PayPage(price int64) (string, error) {
return "wexinPay", nil
}

type PayType int8

const (
AliPayType = 1
WexinPayType = 2
)

type PayFactory interface {
CreatePay() Pay
}

type AliPayFactory struct{}

func (p *AliPayFactory) CreatePay() Pay {
//xxxx
return &AliPay{}
}

type WexinPayFactory struct{}

func (p *WexinPayFactory) CreatePay() Pay {
//xxx
return &WexinPay{}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package factory_method

import (
"fmt"
"testing"
)

func TestPayPage(t *testing.T) {
aliPayFactory := AliPayFactory{}
aliPay := aliPayFactory.CreatePay()
fmt.Println(aliPay.PayPage(1))

wexinPayFactory := WexinPayFactory{}
wexinPay := wexinPayFactory.CreatePay()
fmt.Println(wexinPay.PayPage(1))
}

使用确实麻烦了,但是修改微信支付,不会影响到其他支付。扩展新的支付方式更容易。

创建型模式-抽象工厂模式

每个工厂类可以创建一组相关产品,强调产品族的概念。

使用场景:需要创建一组相关对象的场景。

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
67
68
69
70
71
72
73
74
package abstract_method

import "fmt"

type Pay interface {
PayPage(price int64) (string, error)
}

type AliPay struct{}

func (p *AliPay) PayPage(price int64) (string, error) {
return "aliPay", nil
}

type WexinPay struct{}

func (p *WexinPay) PayPage(price int64) (string, error) {
return "wexinPay", nil
}

type PayType int8

const (
AliPayType = 1
WexinPayType = 2
)

type PayFactory interface {
CreatePay() Pay
CreateRefund() Refund
}

type AliPayFactory struct{}

func (p *AliPayFactory) CreatePay() Pay {
//xxxx
return &AliPay{}
}

type WexinPayFactory struct{}

func (p *WexinPayFactory) CreatePay() Pay {
//xxx
return &WexinPay{}
}

// 退款产品
type Refund interface {
Refund(orderNo string) error
}

type AliRefund struct{}

func (p *AliRefund) Refund(orderNo string) error {
fmt.Println("ali 退款")
return nil
}

type WexinRefund struct{}

func (p *WexinRefund) Refund(orderNo string) error {
fmt.Println("wx 退款")
return nil
}

func (p *AliPayFactory) CreateRefund() Refund {
return &AliRefund{}

}

func (p *WexinPayFactory) CreateRefund() Refund {
return &WexinRefund{}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package abstract_method

import (
"fmt"
"testing"
)

func TestPayPage(t *testing.T) {
aliPayFactory := AliPayFactory{}
aliPay := aliPayFactory.CreatePay()
fmt.Println(aliPay.PayPage(1))
aliPayFactory.CreateRefund().Refund("")

wexinPayFactory := WexinPayFactory{}
wexinPay := wexinPayFactory.CreatePay()
fmt.Println(wexinPay.PayPage(1))
wexinPayFactory.CreateRefund().Refund("")
}

创建型模式-建造者模式

核心思想: 分步构建复杂对象。 将复杂对象的构建过程分离,分步。 体现单一职责

适用场景:

  • 对象的构建过程复杂,包含多个步骤
  • 对象构建过程需要支持不通的配置

比如要建立房子, 需要以下几个元素
房子:最终制品
建造规范:制定包工头需要符合的规范
包工头:按照建造规范建,交付房子
老板:告诉包工头建什么样的房子,获取房子

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

import "fmt"

type House struct {
Door string
Window string
}

// 建造规范,制定包工头需要符合的规范
type HouseBuilder interface {
buildDoor(val string)
buildWindow(val string)
getHouse() *House
}

// 包工头负责,按照老板的要求建造房子,交付房子
type Bao struct {
house *House
}

func (b *Bao) getHouse() *House {
return b.house
}

func (b *Bao) buildDoor(val string) {
b.house.Door = val
fmt.Println("门建造成功")
}

func (b *Bao) buildWindow(val string) {
b.house.Window = val
fmt.Println("窗户建造成功")
}

func NewBao() *Bao {
return &Bao{
house: &House{},
}
}

// 老板负责管理包工头,负责告诉包工头建造怎么样的房子
type Boss struct {
builder HouseBuilder
}

func NewBoss(bao *Bao) *Boss {
return &Boss{
builder: bao,
}
}

func (b *Boss) GetHouse() *House {
b.builder.buildDoor("dor")
b.builder.buildWindow("win")
return b.builder.getHouse()
}
1
2
3
4
5
6
7
8
9
10
11
12
package builder

import (
"fmt"
"testing"
)

func TestNewBao(t *testing.T) {
b := NewBao()
boss := NewBoss(b)
fmt.Println(boss.GetHouse())
}

创建型模式-原型模式

通过复制现有对象来创建新对象,而不是通过新建类的方式。

避免重复初始化,特别适用于创建成本较高的对象。

局限:如果遇到应用类型,需要考虑深拷贝浅拷贝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package prototype

type Prototype interface {
Clone() Prototype
}

type Student struct {
Name string
Age int
}

func (s *Student) Clone() Prototype {
return &Student{
Name: s.Name,
Age: s.Age,
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package prototype

import (
"fmt"
"testing"
)

func TestStudent_Clone(t *testing.T) {
s1 := Student{
Name: "xxx",
Age: 18,
}
s2 := s1.Clone().(*Student)
s2.Name = "yyyy"
s2.Age = 111
fmt.Println(s1)
fmt.Println(s2)
}
  • 本文标题:再次通过创建型模式视角回顾Go
  • 本文作者:形而上
  • 创建时间:2022-07-01 00:00:00
  • 本文链接:https://deepter.gitee.io/2022_07_01_go_design_pattern/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!