常用设计模式整理

工厂模式

概念: 用于用于创建不同但相关类型的对象(继承同一个子类或者接口的一组子类),根据给定的创建参数确定创建哪种子类对象。

种类:

  1. 简单工厂
  2. 工厂方法
  3. 抽象工厂

使用场景:

  • 代码复用:抽离复用创建代码
  • 在无法准确确定对象类别和依赖关系时使用
  • 易扩展,添加新类型重写方法即可

简单工厂

设想一个场景,我们需要根据不同文件类型解析文件内容。比如文件有 .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"))
}

抽象工厂

当工厂方法更加复杂后,基于一组工厂方法可以演化为抽象工厂。
可以创建一系列相关或相互依赖的对象,无需指定具体类。
比如一组对象有依赖关系:
运输工具+ 引擎 + 控制器, 这里工具引擎控制器 都是工厂方法,下面是各自的具体类型:

  1. 汽车+ 内燃机 + 方向盘
  2. 飞机 + 喷气式发动机 + 操纵杆

单例模式

概念: 确保一个类只有一个实例,并提供一个全局访问点。

使用场景:

  • 需要共享资源的场景
  • 需要全局访问点
  • 需要唯一实例的场景

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)
}
0%