【Design Patterns】创建型模式

Posted by Qfrost on 2021-10-09
Estimated Reading Time 15 Minutes
Words 3.8k In Total
Viewed Times

工厂模式(Factory Method)

意图:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

主要解决:主要解决接口选择的问题。

何时使用:我们明确地计划不同条件下创建不同实例时。

如何解决:让其子类实现工厂接口,返回的也是一个抽象的产品。

关键代码:创建过程在其子类执行。

应用实例: 需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。

优点:

  1. 一个调用者想创建一个对象,只要知道其名称就可以了。
  2. 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。
  3. 屏蔽产品的具体实现,调用者只关心产品的接口。

缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

使用场景:

  1. 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。
  2. 数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
  3. 设计一个连接服务器的框架,需要三个协议,“POP3”、“IMAP”、“HTTP”,可以把这三个作为产品类,共同实现一个接口。

注意事项:作为一种创建类模式,在任何需要生成复杂对象的地方,都可以使用工厂方法模式。有一点需要注意的地方就是复杂对象适合使用工厂模式,而简单对象,特别是只需要通过 new 就可以完成创建的对象,无需使用工厂模式。如果使用工厂模式,就需要引入一个工厂类,会增加系统的复杂度。

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
#-*- coding:utf-8 -*-

class Shape(object):
'''
父类充当Interface
'''
def draw(self):
raise NotImplementedError

class Circle(Shape):
'''
Shape子类
'''
def draw(self):
print('draw circle')

class Rectangle(Shape):
'''
Shape的子类
'''
def draw(self):
print('draw Rectangle')


class ShapeFactory(object):
'''
工厂模式:暴露给用户去调用的,
用户可通过该类进行选择Shape的子类进行实例化
'''
def create(self, shape):
if shape == "Circle":
return Circle()
elif shape == "Rectangle":
return Rectangle()
else:
return None

if __name__ == "__main__":
fac = ShapeFactory() #实例化工厂类
obj = fac.create('Circle') #实例化Shape的Circle子类
obj.draw()

抽象工厂模式(Abstract Factory Pattern)

抽象工厂模式(Abstract Factory Pattern)是围绕一个超级工厂创建其他工厂。该超级工厂又称为其他工厂的工厂。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。在抽象工厂模式中,接口是负责创建一个相关对象的工厂,不需要显式指定它们的类。每个生成的工厂都能按照工厂模式提供对象。

意图:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

主要解决:主要解决接口选择的问题。

何时使用:系统的产品有多于一个的产品族,而系统只消费其中某一族的产品。

如何解决:在一个产品族里面,定义多个产品。

关键代码:在一个工厂里聚合多个同类产品。

应用实例:工作了,为了参加一些聚会,肯定有两套或多套衣服吧,比如说有商务装(成套,一系列具体产品)、时尚装(成套,一系列具体产品),甚至对于一个家庭来说,可能有商务女装、商务男装、时尚女装、时尚男装,这些也都是成套的,即一系列具体产品。假设一种情况,在您的家中,某一个衣柜(具体工厂)只能存放某一种这样的衣服(成套,一系列具体产品),每次拿这种成套的衣服时也自然要从这个衣柜中取出了。用 OOP 的思想去理解,所有的衣柜(具体工厂)都是衣柜类的(抽象工厂)某一个,而每一件成套的衣服又包括具体的上衣(某一具体产品),裤子(某一具体产品),这些具体的上衣其实也都是上衣(抽象产品),具体的裤子也都是裤子(另一个抽象产品)。

优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。

缺点:产品族扩展非常困难,要增加一个系列的某一产品,既要在抽象的 Creator 里加代码,又要在具体的里面加代码。

使用场景: 1、QQ 换皮肤,一整套一起换。 2、生成不同操作系统的程序。

花里胡哨说(抄)了一大堆,总结一下就是上面的工厂模式的进化,要有多个工厂,每个工厂生产一类,然后再在上面抽象一层,实现个工厂用来生成工厂,即抽象工厂生产工厂,工厂生产产品(目标实例)

PS:发现python也有抽象类,顺带学了一手

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
#-*- coding:utf-8 -*-
import abc

# 定义形状抽象类
class Shape(metaclass=abc.ABCMeta):
# 定义抽象方法
@abc.abstractclassmethod
def draw(self):
raise NotImplementedError

class Circle(Shape):
def draw(self):
print('draw circle')
class Rectangle(Shape):
def draw(self):
print('draw Rectangle')


# 定义颜色抽象类
class Color(metaclass=abc.ABCMeta):
@abc.abstractclassmethod
def fill(self):
raise NotImplementedError

class Red(Color):
def fill(self):
print("fill Red")
class Green(Color):
def fill(self):
print("fill Green")
class Blue(Color):
def fill(self):
print("fill Blue")


# 定义抽象工厂
class AbstractFactory(metaclass=abc.ABCMeta):
@abc.abstractclassmethod
def getColor(self):
raise NotImplementedError
@abc.abstractclassmethod
def getShape(self):
raise NotImplementedError

# 定义形状工厂
class ShapeFactory(AbstractFactory):
def getShape(self, shape):
if shape == "Circle":
return Circle()
elif shape == "Rectangle":
return Rectangle()
else:
return None
def getColor(self, color):
return None

# 定义颜色工厂
class ColorFactory(AbstractFactory):
def getShape(self, shape):
return None
def getColor(self, color):
if color == "Red":
return Red()
elif color == "Green":
return Green()
elif color == "Blue":
return Blue()
else:
return None

# 创建工厂生成器
class FactoryProducer(object):
@classmethod
def getFactory(cls, choice):
if choice == "SHAPE":
return ShapeFactory()
elif choice == "COLOR":
return ColorFactory()
else:
return None

if __name__ == "__main__":
shape_factory = FactoryProducer.getFactory("SHAPE") # 创建Shape工厂
circle = shape_factory.getShape("Circle") # 创建Circle对象
circle.draw() # 输出

color_factory = FactoryProducer.getFactory("COLOR") # 创建Color工厂
red = color_factory.getColor("Red") # 创建Red对象
red.fill() # 输出

单例模式(Singleton Pattern)

单例模式提供了一种创建对象的最佳方式。这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

即:

  1. 单例类只能有一个实例。
  2. 单例类必须自己创建自己的唯一实例。
  3. 单例类必须给所有其他对象提供这一实例。

意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

主要解决:一个全局使用的类频繁地创建与销毁。

何时使用:当您想控制实例数目,节省系统资源的时候。

如何解决:判断系统是否已经有这个单例,如果有则返回,如果没有则创建。

关键代码:构造函数是私有的

注意事项:getInstance() 方法中需要使用同步锁 synchronized (Singleton.class) 防止多线程同时进入造成 instance 被多次实例化。

单例模式平时写的可能会比较多,而且各个语言的实现方式相差比较大

先码上Python的实现方法,核心是重写__new__方法,但python…搞这些东西确实坑略多

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
#-*- coding:utf-8 -*-

# 重写了__new__方法实现单例
# 将实例放到cls._instance,没事__new__就检查这个成员,若存在则返回,否则创建单例
class SingleObject(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
orig = super(SingleObject, cls) # 获得SingleObject的父类,即object
cls._instance = orig.__new__(cls)
return cls._instance

def __init__(self, class_name=""):
if class_name != "":
self.class_name = class_name

# 继承单例类
class Student(SingleObject):
def __init__(self, class_name, name):
super(Student, self).__init__(class_name)
self.name = name

if __name__ == "__main__":
# 证明a和b为同一个对象
a = SingleObject("class1")
b = SingleObject()
print(a.class_name, b.class_name)
print(id(a), id(b))

# 证明python下重写__new__方法实现单例模式,依旧会调用构造函数修改成员变量
a = SingleObject("class1")
print(a.class_name)
c = SingleObject("class2")
print(a.class_name, b.class_name)

# 证明单例类的派生类依旧服从单例,且若用基类或兄弟类创建单例,也将创建不了本类对象
s1 = Student("class1", "Q1")
s2 = Student("class2", "Q2")
print(s1.class_name, s1.name)
print(s2.class_name, s2.name)

单例模式在C++中实现起来就很简单了,可以定义一个private成员,保存instance指针;或者直接在getInstance方法中定义静态成员保存单例,直接返回单例的引用更加方便

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
class SingleObject
{
private:
SingleObject() {printf("Call SingleObject()\n");};

public:
~SingleObject() {};
static SingleObject& getInstance() {
static SingleObject instance;
return instance;
}
};

int main() {
SingleObject sobj1 = SingleObject::getInstance();
SingleObject sobj2 = SingleObject::getInstance();
printf("%p %p\n", *(size_t*)&sobj1, *(size_t*)&sobj2); // 输出两对象指针,相同,证明单例

return 0;
}

建造者模式(Builder Pattern)

建造者模式使用多个简单的对象一步一步构建成一个复杂的对象。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。一个 Builder 类会一步一步构造最终的对象。该 Builder 类是独立于其他对象的。

意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。

主要解决:主要解决在软件系统中,有时候面临着"一个复杂对象"的创建工作,其通常由各个部分的子对象用一定的算法构成;由于需求的变化,这个复杂对象的各个部分经常面临着剧烈的变化,但是将它们组合在一起的算法却相对稳定。

何时使用:一些基本部件不会变,而其组合经常变化的时候。

如何解决:将变与不变分离开。

应用实例: 肯德基,汉堡、可乐、薯条、炸鸡翅等是不变的,而其组合是经常变化的,生成出所谓的"套餐"。

注意事项:与工厂模式的区别是:建造者模式更加关注与零件装配的顺序。

代码一大堆,描述一大坨。关键其实就是把订单类拆分开来。将“构建”和“表示”分离,以达到解耦的作用。在下面这个订单的构建过程中,如果将order直接通过参数定义好(其构建与表示没有分离),同时在多处进行订单生成,此时需要修改订单内容,则需要一处处去修改,业务风险也就提高了不少。

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
#-*- coding:utf-8 -*-

# 主餐类
class Burger():
name=""
price=0.0
def getPrice(self):
return self.price
def setPrice(self,price):
self.price=price
def getName(self):
return self.name
class CheeseBurger(Burger):
def __init__(self):
self.name="cheese burger"
self.price=10.0
class SpicyChickenBurger(Burger):
def __init__(self):
self.name="spicy chicken burger"
self.price=15.0

# 小食类
class Snack():
name = ""
price = 0.0
type = "SNACK"
def getPrice(self):
return self.price
def setPrice(self, price):
self.price = price
def getName(self):
return self.name
class Chips(Snack):
def __init__(self):
self.name = "chips"
self.price = 6.0
class ChickenWings(Snack):
def __init__(self):
self.name = "chicken wings"
self.price = 12.0

# 饮料类
class Beverage():
name = ""
price = 0.0
type = "BEVERAGE"
def getPrice(self):
return self.price
def setPrice(self, price):
self.price = price
def getName(self):
return self.name
class Coke(Beverage):
def __init__(self):
self.name = "coke"
self.price = 4.0
class Milk(Beverage):
def __init__(self):
self.name = "milk"
self.price = 5.0

# 订单类
class Order():
burger=[]
snack=[]
beverage=[]
def __init__(self,orderBuilder):
self.burger=orderBuilder.bBurger
self.snack=orderBuilder.bSnack
self.beverage=orderBuilder.bBeverage
def show(self):
print("Burger:", [x.getName() for x in self.burger])
print("Snack:", [x.getName() for x in self.snack])
print("Beverage:", [x.getName() for x in self.beverage])
print( "Price:", sum( [x.getPrice() for x in self.burger+self.snack+self.beverage] ) )

# 订单建造者类
class orderBuilder():
bBurger=[]
bSnack=[]
bBeverage=[]
def addBurger(self,xBurger):
self.bBurger.append(xBurger)
def addSnack(self,xSnack):
self.bSnack.append(xSnack)
def addBeverage(self,xBeverage):
self.bBeverage.append(xBeverage)
def build(self):
return Order(self)

if __name__=="__main__":
order_builder=orderBuilder()
order_builder.addBurger(SpicyChickenBurger())
order_builder.addSnack(Chips())
order_builder.addBeverage(Milk())
order_1=order_builder.build()
order_1.show()

原型模式(Prototype Pattern)

原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

主要解决:在运行期建立和删除原型。

如何解决:利用已有的一个原型对象,快速地生成和原型对象一样的实例。

核心思想就是利用实例的复制来代替实例的构造,以节省复杂对象构造时的大量时间开销。涉及复制就有了浅复制和深复制两个概念,本文不对这两个概念详细阐述,不懂的自行百度。 Java实现原型模式非常简单,可以继承 Cloneable,重写 clone();.NET 中可以使用 Object 类的 MemberwiseClone() 方法来实现对象的浅拷贝或通过序列化的方式来实现深拷贝。 在Python中也很方便,实现一下函数调用copy.copy() 或 copy.deepcopy()即可。

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
#-*- coding:utf-8 -*-
from copy import copy, deepcopy

# 实现一个图层类
class simpleLayer:
background=[0,0,0,0]
content="blank"
def getContent(self):
return self.content
def getBackgroud(self):
return self.background
def paint(self,painting):
self.content=painting
def setParent(self,p):
self.background[3]=p
def fillBackground(self,back):
self.background=back
def clone(self): # 浅复制本图层
return copy(self)
def deep_clone(self): # 深复制本图层
return deepcopy(self)

if __name__=="__main__":
dog_layer=simpleLayer()
dog_layer.paint("Dog")
dog_layer.fillBackground([0,0,255,0])
print("Background:",dog_layer.getBackgroud())
print("Painting:",dog_layer.getContent())


dog_layer_clone=dog_layer.clone() # 浅复制这个图层
dog_layer_deepclone = dog_layer.deep_clone() # 深复制这个图层

dog_layer_clone.setParent(64) # 修改浅复制的图层数据
dog_layer_deepclone.setParent(128) # 修改浅复制的图层数据

print("Background:",dog_layer.getBackgroud()) # 输出原图层信息
print("Painting:",dog_layer.getContent())
print("Clone Background:",dog_layer_clone.getBackgroud()) # 输出浅复制图层信息
print("Clone Painting:",dog_layer_clone.getContent())
print("DeepClone Background:",dog_layer_deepclone.getBackgroud()) # 输出深复制图层信息
print("DeepClone Painting:",dog_layer_deepclone.getContent())

# 原图层数据随着浅复制图层数据的修改而修改,深复制图层数据不受影响