0%

设计模式

1.创建型

1.1.工厂模式

核心思想:不再提供一个统一的工厂类来创建所有产品,而是为每个产品提供一个对应的工厂。

这里拿数据库举例:

在web项目开发过程中,会涉及到数据库,假设这里有两种数据库,我们需要创建它们对应的连接,mysqlConnection,postgresConnection,编一个工厂方法的代码

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 CreationalPattern

import "fmt"

// ============databases==============
type DBConnection interface {
Connect() string
Query(sql string) string
}

type MysqlConnection struct {
host string
port int
}

func (m *MysqlConnection) Connect() string {
return fmt.Sprintf("Connected to MySQL at %s:%d", m.host, m.port)
}

func (m *MysqlConnection) Query(sql string) string {
return fmt.Sprintf("Query from MySQL using sql:%s", sql)
}

type PostgresConnection struct {
host string
port int
}

func (p *PostgresConnection) Connect() string {
return fmt.Sprintf("Connected to Postgres at %s:%d", p.host, p.port)
}

func (p *PostgresConnection) Query(sql string) string {
return fmt.Sprintf("Query from Postgres using sql:%s", sql)
}

// ==============factory==============
type DBFactory interface {
CreateConnection(host string, port int) DBConnection
}

type MysqlFactory struct{}

func (m MysqlFactory) CreateConnection(host string, port int) DBConnection {
return &MysqlConnection{host: host, port: port}
}

type PostgresFactory struct{}

func (m PostgresFactory) CreateConnection(host string, port int) DBConnection {
return &PostgresConnection{host: host, port: port}
}

main函数测试

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

import (
"DesignPattern/CreationalPattern"
"fmt"
)

func main() {
var factory CreationalPattern.DBFactory
dbType := "mysql"
switch dbType {
case "mysql":
factory = CreationalPattern.MysqlFactory{}
case "postgres":
factory = CreationalPattern.PostgresFactory{}
default:
panic("Unsupported database type")
}
// create the database connection
conn := factory.CreateConnection("10.100.167.1", 8080)
fmt.Println(conn.Connect())
fmt.Println(conn.Query("select * from abc"))
}

运行结果

1
2
Connected to MySQL at 10.100.167.1:8080
Query from MySQL using sql:select * from abc

1.2.抽象工厂模式

抽象工厂模式提供了一种方式,可以创建一系列相关或相互依赖的对象,而无需指定它们具体的类。

这里使用Apple和xiaomi两家品牌举例

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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package CreationalPattern

import "fmt"

// =======抽象产品接口=======
type Phone interface {
getName() string
getPhoneCamera() string
getSoc() string
}

type Laptop interface {
getName() string
getCpu() string
getMemory() string
}

// =========具体产品:苹果系列===========
type Iphone struct {
Name string
Soc string
PhoneCamera string
}

func NewIphone() *Iphone {
return &Iphone{
Name: "iphone17",
Soc: "A18",
PhoneCamera: "sony",
}
}

func (i *Iphone) getName() string {
return i.Name
}
func (i *Iphone) getPhoneCamera() string {
return i.PhoneCamera
}
func (i *Iphone) getSoc() string {
return i.Soc
}

type MacBookPro struct {
Name string
Cpu string
Memory string
}

func NewMacBookPro() *MacBookPro {
return &MacBookPro{
Name: "MacBookPro",
Cpu: "m5",
Memory: "32G",
}
}

func (m *MacBookPro) getName() string {
return m.Name
}
func (m *MacBookPro) getCpu() string {
return m.Cpu
}
func (m *MacBookPro) getMemory() string {
return m.Memory
}

// ===========具体产品:小米系列=============
type MiPhone struct {
Name string
Soc string
PhoneCamera string
}

func NewMiPhone() *MiPhone {
return &MiPhone{
Name: "小米17",
Soc: "骁龙至尊版第五代",
PhoneCamera: "徕卡",
}
}
func (m *MiPhone) getName() string {
return m.Name
}
func (m *MiPhone) getPhoneCamera() string {
return m.PhoneCamera
}
func (m *MiPhone) getSoc() string {
return m.Soc
}

type MiLaptop struct {
Name string
Cpu string
Memory string
}

func NewMiLaptop() *MiLaptop {
return &MiLaptop{
Name: "小米笔记本电脑",
Cpu: "AMD",
Memory: "32G",
}
}
func (m *MiLaptop) getName() string {
return m.Name
}
func (m *MiLaptop) getCpu() string {
return m.Cpu
}
func (m *MiLaptop) getMemory() string {
return m.Memory
}

// ============电子厂==============
type ElectronicFactory interface {
ProducePhone() Phone
ProduceLaptop() Laptop
}

// 苹果工厂
type AppleFactory struct {
Name string
}

func (f *AppleFactory) ProducePhone() Phone {
return NewIphone()
}
func (f *AppleFactory) ProduceLaptop() Laptop {
return NewMacBookPro()
}

// 小米工厂
type XiaomiFactory struct {
Name string
}

func (f *XiaomiFactory) ProducePhone() Phone {
return NewMiPhone()
}
func (f *XiaomiFactory) ProduceLaptop() Laptop {
return NewMiLaptop()
}

func ShowEcosystem(factory ElectronicFactory) {
fmt.Println("*************生态系统************")
phone := factory.ProducePhone()
fmt.Println("手机信息:")
fmt.Printf("name is %s\n", phone.getName())
fmt.Printf("soc is %s\n", phone.getSoc())
fmt.Printf("phonecamera is %s\n", phone.getPhoneCamera())
laptop := factory.ProduceLaptop()
fmt.Println("电脑信息:")
fmt.Printf("name is %s\n", laptop.getName())
fmt.Printf("cpu is %s\n", laptop.getCpu())
fmt.Printf("memory is %s\n", laptop.getMemory())
}

main函数测试

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

import (
"DesignPattern/CreationalPattern"
"fmt"
)

func main() {
appleFactory := &CreationalPattern.AppleFactory{
Name: "Apple",
}
fmt.Printf("=============%s工厂=============\n", appleFactory.Name)
CreationalPattern.ShowEcosystem(appleFactory)
xiaomiFactory := &CreationalPattern.XiaomiFactory{
Name: "Xiaomi",
}
fmt.Printf("=============%s工厂=============\n", xiaomiFactory.Name)
CreationalPattern.ShowEcosystem(xiaomiFactory)
}

运行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
=============Apple工厂=============
*************生态系统************
手机信息:
name is iphone17
soc is A18
phonecamera is sony
电脑信息:
name is MacBookPro
cpu is m5
memory is 32G
=============Xiaomi工厂=============
*************生态系统************
手机信息:
name is 小米17
soc is 骁龙至尊版第五代
phonecamera is 徕卡
电脑信息:
name is 小米笔记本电脑
cpu is AMD
memory is 32G

1.3.原型模式

原型模式是指通过复制现有对象来创建新对象,而不是通过实例化类。当对象创建成本较高(如需要复杂计算、大量数据库查询)或者希望保持对象状态时特别有用。

下面使用深浅拷贝举例。

1.3.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
package CreationalPattern

import "fmt"

// 原型接口
type Cloneable interface {
Clone() Cloneable
}
type Address struct {
City string
}

type Person struct {
Name string
Age int
Email string
Address Address // 值类型字段
}

func (p *Person) Clone() Cloneable {
clone := &Person{
Name: p.Name,
Age: p.Age,
Email: p.Email,
Address: p.Address,
}
return clone
}

func (p *Person) String() string {
return fmt.Sprintf("Person{Name:%s, Age:%d, Email:%s, Address:%+v}",
p.Name, p.Age, p.Email, p.Address)
}

main函数测试

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

import (
"DesignPattern/CreationalPattern"
"fmt"
)

func main() {
// 创建原型对象
original := &CreationalPattern.Person{
Name: "Mike",
Age: 18,
Email: "mike@gmail.com",
Address: CreationalPattern.Address{
City: "上海",
},
}

// 克隆对象
cloned := original.Clone().(*CreationalPattern.Person)
fmt.Println("原始对象:", original)
fmt.Println("克隆对象:", cloned)

// 修改克隆对象
cloned.Name = "Tim"
cloned.Address.City = "杭州"

fmt.Println("\n修改后:")
fmt.Println("原始对象:", original)
fmt.Println("克隆对象:", cloned)
}

运行结果

1
2
3
4
5
6
原始对象: Person{Name:Mike, Age:18, Email:mike@gmail.com, Address:{City:上海}}
克隆对象: Person{Name:Mike, Age:18, Email:mike@gmail.com, Address:{City:上海}}

修改后:
原始对象: Person{Name:Mike, Age:18, Email:mike@gmail.com, Address:{City:上海}}
克隆对象: Person{Name:Tim, Age:18, Email:mike@gmail.com, Address:{City:杭州}}

1.3.2.举例深拷贝:

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
type DeepCloneable interface {
DeepClone() DeepCloneable
}

type Employee struct {
Name string
Age int
Department string
PhoneNumber int
Skills []Skill
}
type Skill struct {
Name string
Level int
Tags []string
}

func (e *Employee) DeepClone() DeepCloneable {
skillsCopy := make([]Skill, len(e.Skills))
for i, skill := range e.Skills {
tagsCopy := make([]string, len(skill.Tags))
copy(tagsCopy, skill.Tags)
skillsCopy[i] = Skill{
Name: skill.Name,
Level: skill.Level,
Tags: tagsCopy,
}
}
return &Employee{
Name: e.Name,
Age: e.Age,
Department: e.Department,
PhoneNumber: e.PhoneNumber,
Skills: skillsCopy,
}
}

func (e *Employee) String() string {
return fmt.Sprintf("Employee{Name:%s, Age:%v, Deparment:%s, PhoneNumber:%v, Skills:%+v}",
e.Name, e.Age, e.Department, e.PhoneNumber, e.Skills)
}

main函数测试

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 (
"DesignPattern/CreationalPattern"
"fmt"
)

func main() {
original := &CreationalPattern.Employee{
Name: "John Smith",
Department: "Employee",
Age: 18,
PhoneNumber: 15599996666,
Skills: []CreationalPattern.Skill{
{Name: "golang", Level: 3, Tags: []string{"后端", "IO操作"}},
{Name: "python", Level: 5, Tags: []string{"脚本", "AI"}},
},
}
clone := original.DeepClone()
fmt.Printf("原对象: %+v\n", original)
fmt.Printf("克隆对象: %+v\n", clone)

clone.Name = "bob"
clone.PhoneNumber = 11188887777
clone.Skills[0].Level = 6

fmt.Printf("修改后克隆对象: %+v\n", original)
fmt.Printf("Skills 切片地址是否相同: 原始%p 克隆%p\n", &original.Skills, &clone.Skills)
}

运行结果

1
2
3
4
原对象: Employee{Name:John Smith, Age:18, Deparment:Employee, PhoneNumber:15599996666, Skills:[{Name:golang Level:3 Tags:[后端 IO操作]} {Name:python Level:5 Tags:[脚本 AI]}]}
克隆对象: Employee{Name:John Smith, Age:18, Deparment:Employee, PhoneNumber:15599996666, Skills:[{Name:golang Level:3 Tags:[后端 IO操作]} {Name:python Level:5 Tags:[脚本 AI]}]}
修改后克隆对象: Employee{Name:John Smith, Age:18, Deparment:Employee, PhoneNumber:15599996666, Skills:[{Name:golang Level:3 Tags:[后端 IO操作]} {Name:python Level:5 Tags:[脚本 AI]}]}
Skills 切片地址是否相同: 原始0xc00010a030 克隆0xc00010a080

1.4.生成器模式

生成器模式将复杂对象构建的过程和表现形式分离

适用场景:对象构建过程需要多个步骤,不同的表现形式

这里就用典型的配置构建来演示

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

import (
"errors"
"fmt"
"time"
)

type ServerConfig struct {
Host string
Port int
Timeout time.Duration
EnableSSL bool
MaxConnections int
}

type ConfigBuilder struct {
Config *ServerConfig
Errors []error
}

func (cb *ConfigBuilder) Host(host string) *ConfigBuilder {
cb.Config.Host = host
return cb
}

func (cb *ConfigBuilder) Port(port int) *ConfigBuilder {
if port < 1 || port > 65535 {
cb.Errors = append(cb.Errors, errors.New("'port must be between 1 and 65535'"))
}
cb.Config.Port = port
return cb
}

func (cb *ConfigBuilder) Timeout(timeout time.Duration) *ConfigBuilder {
cb.Config.Timeout = timeout
return cb
}

func (cb *ConfigBuilder) EnableSSL(enableSSL bool) *ConfigBuilder {
cb.Config.EnableSSL = enableSSL
return cb
}
func (cb *ConfigBuilder) MaxConnections(maxConnections int) *ConfigBuilder {
if maxConnections < 1 {
cb.Errors = append(cb.Errors, errors.New("'max connections must be greater than zero'"))
}
cb.Config.MaxConnections = maxConnections
return cb
}

func (cb *ConfigBuilder) Build() (*ServerConfig, error) {
if len(cb.Errors) > 0 {
return nil, fmt.Errorf("validation errors %v", cb.Errors)
}
return cb.Config, nil
}

func NewConfigBuilder() *ConfigBuilder {
return &ConfigBuilder{
Config: &ServerConfig{
Host: "localhost",
Port: 8080,
Timeout: time.Second * 15,
EnableSSL: false,
MaxConnections: 10,
},
}
}

main函数测试

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

import (
"DesignPattern/CreationalPattern"
"fmt"
)

func main() {
config, err := CreationalPattern.NewConfigBuilder().
Host("10.12.13.14").
Port(6379).
EnableSSL(true).
MaxConnections(10000).
Build()
if err != nil {
panic(err)
}
fmt.Printf("%+v\n", config)
}

运行结果

1
&{Host:10.12.13.14 Port:6379 Timeout:15s EnableSSL:true MaxConnections:10000}

1.5.单例模式

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

1.5.1.饿汉式示例

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

import "time"

type Singleton struct {
Value int
}
// 因为包级变量会优先于main完成一次初始化,所以不管多个线程怎么调用永远是这一个实例
var instance1 *Singleton = &Singleton{100}

func GetInstance1() *Singleton {
return instance1
}

main函数测试

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 (
"DesignPattern/CreationalPattern"
"fmt"
"sync"
)

func main() {
var wg sync.WaitGroup
hashMap := sync.Map{}
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
inst := CreationalPattern.GetInstance1()
hashMap.Store(inst, true)
fmt.Printf("goroutine %d got instance: %p value=%d\n",
i, inst, inst.Value)
}(i)
}
wg.Wait()
count := 0
hashMap.Range(func(key, value interface{}) bool {
count++
return true
})
fmt.Println("different instance count:", count)
}

运行结果

1
2
3
4
5
6
7
8
9
10
11
12
goroutine 0 got instance: 0x7ff61d438580 value=100
goroutine 1 got instance: 0x7ff61d438580 value=100
goroutine 3 got instance: 0x7ff61d438580 value=100
goroutine 5 got instance: 0x7ff61d438580 value=100
goroutine 4 got instance: 0x7ff61d438580 value=100
goroutine 7 got instance: 0x7ff61d438580 value=100
goroutine 2 got instance: 0x7ff61d438580 value=100
goroutine 8 got instance: 0x7ff61d438580 value=100
goroutine 6 got instance: 0x7ff61d438580 value=100
goroutine 9 got instance: 0x7ff61d438580 value=100
different instance count: 1

1.5.2.懒汉式示例(线程不安全)

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

import "time"

type Singleton struct {
Value int
}

var instance2 *Singleton

func GetInstance2() *Singleton {
if instance2 == nil {
// 人为放大竞态窗口
time.Sleep(time.Millisecond)
instance2 = &Singleton{200}
}
return instance2
}

main函数测试

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 (
"DesignPattern/CreationalPattern"
"fmt"
"sync"
)

func main() {
var wg sync.WaitGroup
hashMap := sync.Map{}
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
inst := CreationalPattern.GetInstance2()
hashMap.Store(inst, true)
fmt.Printf("goroutine %d got instance: %p value=%d\n",
i, inst, inst.Value)
}(i)
}
wg.Wait()
count := 0
hashMap.Range(func(key, value interface{}) bool {
count++
return true
})
fmt.Println("different instance count:", count)
}

运行结果

1
2
3
4
5
6
7
8
9
10
11
12
goroutine 8 got instance: 0xc000106060 value=200
goroutine 4 got instance: 0xc00000a090 value=200
goroutine 7 got instance: 0xc00000a060 value=200
goroutine 0 got instance: 0xc00000a068 value=200
goroutine 1 got instance: 0xc00000a038 value=200
goroutine 5 got instance: 0xc000106068 value=200
goroutine 3 got instance: 0xc000106090 value=200
goroutine 6 got instance: 0xc000184000 value=200
goroutine 2 got instance: 0xc000092000 value=200
goroutine 9 got instance: 0xc000288000 value=200
different instance count: 10

1.5.3.标准示例

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

import (
"sync"
)

var (
instance3 *Singleton
once sync.Once
)

func GetInstance3() *Singleton {
// 只会执行一次
once.Do(func() {
instance3 = &Singleton{300}
})
return instance3
}

main函数测试

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 (
"DesignPattern/CreationalPattern"
"fmt"
"sync"
)

func main() {
var wg sync.WaitGroup
hashMap := sync.Map{}
for i := 0; i < 10; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
inst := CreationalPattern.GetInstance3()
hashMap.Store(inst, true)
fmt.Printf("goroutine %d got instance: %p value=%d\n",
i, inst, inst.Value)
}(i)
}
wg.Wait()
count := 0
hashMap.Range(func(key, value interface{}) bool {
count++
return true
})
fmt.Println("different instance count:", count)
}

1
2
3
4
5
6
7
8
9
10
11
12
goroutine 1 got instance: 0xc00000a088 value=300
goroutine 2 got instance: 0xc00000a088 value=300
goroutine 3 got instance: 0xc00000a088 value=300
goroutine 4 got instance: 0xc00000a088 value=300
goroutine 5 got instance: 0xc00000a088 value=300
goroutine 6 got instance: 0xc00000a088 value=300
goroutine 7 got instance: 0xc00000a088 value=300
goroutine 8 got instance: 0xc00000a088 value=300
goroutine 0 got instance: 0xc00000a088 value=300
goroutine 9 got instance: 0xc00000a088 value=300
different instance count: 1