六个创建型模式

阅读之前请对UML有简单的理解
本文所有内容整理自https://blog.csdn.net/LoveLion/article/details/17517213
详细介绍可以点击链接,本文更加侧重于作者个人笔记;

简单工厂模式


image.png

  • Chart:抽象产品;
  • HistogramChart:具体产品类,实现抽象产品接口;
  • ChartFactory:工厂类,用于生产具体的产品,返回抽象产品,由客户端调用;

缺点:当有新的产品的时候,需要修改工厂类,因此适用于创建类少的场景;

工厂模式

不再提供一个统一的工厂类来创建所有的产品对象,而是针对不同的产品提供不同的工厂,系统提供一个与产品等级结构对应的工厂等级结构;


image.png

  • Product:抽象产品接口;
  • ConcreteProduce:具体的产品,实现抽象产品的接口,实现相应的行为;
  • Factory:抽象工厂,提供创建不同产品的同一接口;
  • ConcreteFactory:具体工厂,实现抽象工厂的方法,创建具体的产品,返回值为抽象产品的一个子类;
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
package main

import "fmt"

/*
https://blog.csdn.net/lovelion/article/details/9306745
*/
// 日志记录器接口
type Logger interface {
writeLog()
}

// 数据库日志记录器
type DatabaseLogger struct {
}

// 实现接口
func (d *DatabaseLogger) writeLog() {
fmt.Println("数据库日志.....")
}

// 文件日志记录器
type FileLogger struct {
}

// 实现接口
func (f *FileLogger) writeLog() {
fmt.Println("文件日志记录器......")
}

// 日志记录器的抽象工厂
type LoggerFactory interface {
createLogger() Logger
}

// 数据库的具体工厂
type DatabaseLoggerFactory struct {
}

func (d *DatabaseLoggerFactory) createLogger() Logger {
// 连接数据库
// 创建数据库日志记录器对象
var logger Logger
logger = new(DatabaseLogger)
return logger
}

// 文件日志记录器的具体工厂
type FileLoggerFactory struct {
}

func (f *FileLoggerFactory) createLogger() Logger {
//创建文件日志记录器对象
var logger Logger
logger = new(FileLogger)
return logger
}

func main() {
// 使用抽象工厂来实现生产具体的产品
var factory LoggerFactory
var logger Logger
factory = &DatabaseLoggerFactory{}
logger = factory.createLogger()
logger.writeLog()
}
  • 工厂方法模式是简单工厂模式的延伸,它继承了简单工厂模式的优点,同时还弥补了简单工厂模式的不足。工厂方法模式是使用频率最高的设计模式之一,是很多开源框架和API类库的核心模式。
  • 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销

抽象工厂模式

在工厂模式中,由于存在等级结构,因此也造成了产品和工厂类的增多,每增加一个产品,都要对应编写相应的方法,因此为了解决这个问题,引入产品族的概念;


有时候我们希望一个工厂可以提供多个产品对象,而不是单一的产品对象,如一个电器工厂,它可以生产电视机、电冰箱、空调等多种电器,而不是只生产某一种电器;


如解决皮肤库的问题:


image.png


两个概念:

  • 产品等级结构:如抽象类为电视机,其子类有海尔电视机,海信电视机,TCL电视机,即一系列的产品;
  • 产品族:如抽象工厂中,同一个工厂生产位于不同等级的一组产品,如海尔电器工厂,生产海尔电冰箱,海尔电视机等;

抽象工厂模式和工厂模式最大的区别在于工厂方法对应的是一个产品等级结构,而抽象工厂方法对应多个产品等级结构;


image.png


皮肤解决方案:

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

import "fmt"

//抽象产品按钮类
type Button interface {
display()
}

//抽象产品文本框类
type TextField interface {
display()
}

//具体产品按钮类
type SpringButton struct {
}
type SummerBUtton struct {
}

func (s *SpringButton) display() {
fmt.Println("浅绿色按钮")
}
func (s *SummerBUtton) display() {
fmt.Println("浅蓝色按钮")
}

//具体产品按钮类
type SpringTextField struct {
}
type SummerTextField struct {
}

func (s *SpringTextField) display() {
fmt.Println("浅绿色文本框")
}
func (s *SummerTextField) display() {
fmt.Println("浅蓝色文本框")
}

///////皮肤工厂接口:抽象接口
type SkinFactory interface {
createButton() Button
createTextField() TextField
}

///////Spring皮肤工厂:具体工厂
type SpringSkinFactory struct {
}

func (*SpringSkinFactory) createButton() Button {
return new(SpringButton)
}
func (*SpringSkinFactory) createTextField() TextField {
return new(SpringTextField)
}

//////Summner皮肤工厂
type SummerSkinFactory struct {
}

func (*SummerSkinFactory) createTextField() TextField {
return new(SummerTextField)
}
func (*SummerSkinFactory) createButton() Button {
return new(SummerBUtton)
}
func main() {
//定义一个抽象工厂
var factory SkinFactory
//定义抽象产品
var bt Button
var tx TextField
factory = &SpringSkinFactory{}
bt = factory.createButton()
tx = factory.createTextField()
bt.display()
tx.display()
}

对于抽象工厂,增加新的产品族,非常方便,只需要添加一个具体的工厂就可以了,但是如果增加新的产品等级,就需要修改所有的角色,包括增加方法,因此在使用抽象工厂设计时,一般需要尽可能的保证产品等级不会发生改变,否则不利于维护;

单例模式

单例模式一般实质,客户端无法创建一个类的实例对象,该实例只能被创建一次,如电脑的任务管理器,始终都是一个窗口。在设计时需要借助私有属性,直接初始化我们的对象,在客户端直接获取;

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

import (
"fmt"
)

type task interface {
}

//单例模式
type taskMannager struct {
}

var (
defaultTaskManger task
sign bool
)

func init() {
if sign == true {
fmt.Println("已经被初始化了")
return
}
defaultTaskManger = &taskMannager{}
}
func GetTask() task {
return defaultTaskManger
}
func main() {

}


上述属于饿汉式,直接初始化了一个对象,如果是懒汉式可以将init函数去掉,合并到GetTask()函数上;

原型模式

该模式是对某一个对象的克隆,可以通过一个原型,克隆出多个一摸一样的对象;


image.png

  • Prototype:抽象原型类,声明了克隆方法的接口,是所有具体原型类的公共父类;
  • ConcretePrototype:具体的原型类,并实现克隆方法,返回自己的克隆对象;
  • Client:客户类,拥有用一个原型对象克隆出一个新的对象;
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
package main

import "fmt"

type Object interface {
clone() Object
}
type Eample struct {
name string
}

func (e *Eample) clone() Object {
res := *e
return &res
}

func main() {
var o Object
o = &Eample{name: "01"}
c1 := o.clone()
value, ok := c1.(*Eample)
if !ok {
fmt.Println("It's not ok for type Example")
return
}
fmt.Println(value.name)
}


上述代码属于深拷贝,因为使用*进行了指针取值,但是如果直接指针赋值,将会出现浅拷贝,修改拷贝后的值,同样也会引起原型的改变;

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

import "fmt"

type Object interface {
clone() Object
}
type Eample struct {
name string
}

func (e *Eample) clone() Object {
res := e
return res
}

func main() {
var o Object
o = &Eample{name: "01"}
c1 := o.clone()
value1, _ := c1.(*Eample)
value2, _ := o.(*Eample)
fmt.Println(value1.name)
value1.name = "02"
fmt.Println(value2.name)
}
//最终输出,修改了克隆对象,但是原型对象也被修改了
/*
01
02
*/

建造者模式

没有人买车会只买一个轮胎或者方向盘,大家买的都是一辆包含轮胎、方向盘和发动机等多个部件的完整汽车。如何将这些部件组装成一辆完整的汽车并返回给用户,这是建造者模式需要解决的问题。建造者模式又称为生成器模式,它是一种较为复杂、使用频率也相对较低的创建型模式。建造者模式为客户端返回的不是一个简单的产品,而是一个由多个部件组成的复杂产品。


image.png

  • Builder:抽象建造者,为创建一个产品对象的各个部件指定抽象接口,在该接口中一般声明两类方法,一类是建造方法,一类是返回复杂对象的方法;
  • ConctreteBuilder:具体的建造者,实现接口的方法;
  • Product:具体的产品;
  • Director:指挥者,负责安排复杂对象的建造次序;