工厂模式
概念:
用于用于创建不同但相关类型的对象(继承同一个子类或者接口的一组子类),根据给定的创建参数确定创建哪种子类对象。
种类:
- 简单工厂
- 工厂方法
- 抽象工厂
使用场景:
- 代码复用:抽离复用创建代码
- 在无法准确确定对象类别和依赖关系时使用
- 易扩展,添加新类型重写方法即可
简单工厂
设想一个场景,我们需要根据不同文件类型解析文件内容。比如文件有 .json.md .yaml .toml····
简单工厂实现的话,需要有负责创建所有类的创建工厂,新增解析器需要修改工厂创建方法。
simple-factory
工厂方法需要负责所有类的创建,新增解析器需要修改工厂创建方
DEMO
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
|
package factory
// 各种解析器需要实现的 parse 功能接口
type IConfigParser interface {
Parse(data []byte)
}
// json 解析器
type jsonConfigParser struct {
}
func (J jsonConfigParser) Parse(data []byte) {
panic("implement me")
}
// yaml 解析器
type yamlConfigParser struct {
}
func (Y yamlConfigParser) Parse(data []byte) {
panic("implement me")
}
// 简单工厂
func NewIConfigParser(t string) IConfigParser { // 返回接口类型
switch t {
case "json":
return jsonConfigParser{}
case "yaml":
return yamlConfigParser{}
}
return nil
}
|
- 适用于创建类型较少,并且对象功能较类似的场景
- 创建对象和使用对象分离,解耦合等场景
工厂方法
当对象创建的逻辑比较复杂时,比如创建的类对象各自依赖许多不同的类,会导致创建逻辑过于复杂,可以通过工厂方法的方式优化将创建逻辑拆到各自的工厂类中。
场景变复杂了
解析器不在局限于文本类型,需要解析其他类型文件,音频、视频等等。
文本类型:json、Markdown···
音频:MP3、acc、m4a···
视频:mp4、flv、avi···
factory-method
工厂方法相当于在简单工厂基础上添加了一层抽象层,抽象的工厂方法用于创建具体的工厂方法。
factory-method2
创建对象延迟到具体的子类中,新增解析器无需改动现有代码。
DEMO
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
|
package main
// 创建具体工厂的接口
type IParserFactory interface {
CreateParser(t string) IParser
}
type IParser interface {
Parse(data []byte)
}
// 文本解析器工厂
type TextParserFactory struct{}
type jsonConfigParser struct{}
type yamlConfigParser struct{}
func (p TextParserFactory) CreateParser(t string) IParser {
switch t {
case "text":
return jsonConfigParser{}
case "video":
return yamlConfigParser{}
}
return nil
}
func (j jsonConfigParser) Parse(data []byte) {
panic("implement")
}
func (y yamlConfigParser) Parse(data []byte) {
panic("implement")
}
// 视频解析器工厂
type VideoParserFactory struct{}
type mp4Parser struct{}
type aviParser struct{}
func (v VideoParserFactory) CreateParser(t string) IParser {
switch t {
case "mp4":
return mp4Parser{}
case "avi":
return aviParser{}
}
return nil
}
func (m mp4Parser) Parse(data []byte) {
panic("implement")
}
func (a aviParser) Parse(data []byte) {
panic("implement")
}
func main() {
// 使用文本解析器工厂创建解析器
textFactory := TextParserFactory{}
textParser := textFactory.CreateParser("text")
textParser.Parse([]byte("text data"))
// 使用视频解析器工厂创建解析器
videoFactory := VideoParserFactory{}
videoParser := videoFactory.CreateParser("mp4")
videoParser.Parse([]byte("video data"))
}
|
抽象工厂
当工厂方法更加复杂后,基于一组工厂方法可以演化为抽象工厂。
可以创建一系列相关或相互依赖的对象,无需指定具体类。
比如一组对象有依赖关系:
运输工具
+ 引擎
+ 控制器
, 这里工具
、引擎
、控制器
都是工厂方法,下面是各自的具体类型:
汽车
+ 内燃机
+ 方向盘
飞机
+ 喷气式发动机
+ 操纵杆
单例模式
概念:
确保一个类只有一个实例,并提供一个全局访问点。
使用场景:
- 需要共享资源的场景
- 需要全局访问点
- 需要唯一实例的场景
DEMO
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package singleton
// Singleton 饿汉式单例
type Singleton struct{}
var singleton *Singleton
func init() {
singleton = &Singleton{}
}
// GetInstance 获取实例
func GetInstance() *Singleton {
return singleton
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
package singleton
import "sync"
var (
lazySingleton *Singleton
once = &sync.Once{}
)
// GetLazyInstance 懒汉式
func GetLazyInstance() *Singleton {
if lazySingleton == nil {
once.Do(func() {
lazySingleton = &Singleton{}
})
}
return lazySingleton
}
|
Builder 模式
概念
Builder 模式是一种创建复杂对象的设计模式,它通过将对象的构造过程分步骤进行,使得同样的构造过程可以创建不同的表示。它将对象的构造与表示分离,使得构造过程可以复用。
使用场景
- 创建对象的构造过程比较复杂
- 创建对象的构造过程需要灵活控制
和工厂模式的区别
builder 模式更加关注对象的创建过程,而工厂模式更加关注对象的创建结果。
DEMO
使用 setter 方式的 builder 模式。
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
|
package main
import "fmt"
// Product 代表要构建的复杂对象
type Product struct {
partA string
partB string
partC string
}
// ProductBuilder 是用于构建 Product 的构建器
type ProductBuilder struct {
product *Product
}
// NewProductBuilder 创建一个新的 ProductBuilder
func NewProductBuilder() *ProductBuilder {
return &ProductBuilder{product: &Product{}}
}
// SetPartA 设置 Product 的 PartA 部分
func (b *ProductBuilder) SetPartA(partA string) *ProductBuilder {
b.product.partA = partA
return b
}
// SetPartB 设置 Product 的 PartB 部分
func (b *ProductBuilder) SetPartB(partB string) *ProductBuilder {
b.product.partB = partB
return b
}
// SetPartC 设置 Product 的 PartC 部分
func (b *ProductBuilder) SetPartC(partC string) *ProductBuilder {
b.product.partC = partC
return b
}
// Build 返回构建好的 Product
func (b *ProductBuilder) Build() *Product {
return b.product
}
func main() {
builder := NewProductBuilder()
product := builder.SetPartA("Part A").
SetPartB("Part B").
SetPartC("Part C").
Build()
fmt.Printf("Product: %+v\n", *product)
}
|
使用 option function 方式的 builder 模式。
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
|
package main
import "fmt"
// Product 代表要构建的复杂对象
type Product struct {
partA string
partB string
partC string
}
// Option 定义了配置 Product 的函数类型
type Option func(*Product)
// NewProduct 创建一个新的 Product 并应用所有选项
func NewProduct(options ...Option) *Product {
product := &Product{}
for _, option := range options {
option(product)
}
return product
}
// WithPartA 返回一个配置 Product 的函数
func WithPartA(partA string) Option {
return func(p *Product) {
p.partA = partA
}
}
// WithPartB 返回一个配置 Product 的函数
func WithPartB(partB string) Option {
return func(p *Product) {
p.partB = partB
}
}
// WithPartC 返回一个配置 Product 的函数
func WithPartC(partC string) Option {
return func(p *Product) {
p.partC = partC
}
}
func main() {
product := NewProduct(
WithPartA("Part A"),
WithPartB("Part B"),
WithPartC("Part C"),
)
fmt.Printf("Product: %+v\n", *product)
}
|
Prototype 模式
概念
Prototype 允许一个对象在创建另一个可定制的对象的实例时,无需重新实例化,而是使用拷贝这个原型对象的方式。原型模式在 js 中使用比较广泛。
使用场景
- 当一个对象的创建过程比较复杂,需要重复创建相似对象时
- 当一个对象需要提供给其他对象访问,而且各个调用者可能需要修改对象的状态时
DEMO
浅拷贝方式
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
|
package main
import (
"fmt"
)
// Cloneable 是一个定义了克隆方法的接口
type Cloneable interface {
Clone() Cloneable
}
// ConcretePrototype 是一个具体的原型对象,实现了 Cloneable 接口
type ConcretePrototype struct {
Name string
Value int
Items []string // 引用类型的属性
}
// Clone 创建并返回当前对象的一个副本(浅拷贝)
func (p *ConcretePrototype) Clone() Cloneable {
// 创建一个新的 ConcretePrototype 对象,并复制当前对象的值
newPrototype := *p
return &newPrototype
}
func main() {
// 创建一个原型对象
original := &ConcretePrototype{
Name: "Original",
Value: 42,
Items: []string{"item1", "item2"},
}
// 通过克隆方法创建一个副本
clone := original.Clone().(*ConcretePrototype)
// 修改副本的值
clone.Name = "Clone"
clone.Value = 100
clone.Items[0] = "modified_item1"
// 打印原型对象和副本对象的值
fmt.Printf("Original: %+v\n", original)
fmt.Printf("Clone: %+v\n", clone)
}
|
深拷贝方式
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
|
package main
import (
"fmt"
)
// Cloneable 是一个定义了克隆方法的接口
type Cloneable interface {
Clone() Cloneable
}
// ConcretePrototype 是一个具体的原型对象,实现了 Cloneable 接口
type ConcretePrototype struct {
Name string
Value int
Items []string // 引用类型的属性
}
// Clone 创建并返回当前对象的一个副本(深拷贝)
func (p *ConcretePrototype) Clone() Cloneable {
// 创建一个新的 ConcretePrototype 对象,并递归复制引用类型属性
newPrototype := *p
newPrototype.Items = make([]string, len(p.Items))
copy(newPrototype.Items, p.Items)
return &newPrototype
}
func main() {
// 创建一个原型对象
original := &ConcretePrototype{
Name: "Original",
Value: 42,
Items: []string{"item1", "item2"},
}
// 通过克隆方法创建一个副本
clone := original.Clone().(*ConcretePrototype)
// 修改副本的值
clone.Name = "Clone"
clone.Value = 100
clone.Items[0] = "modified_item1"
// 打印原型对象和副本对象的值
fmt.Printf("Original: %+v\n", original)
fmt.Printf("Clone: %+v\n", clone)
}
|