This page looks best with JavaScript enabled

【Design Patterns】创建型模式

 ·  ☕ 9 min read · 👀... views

工厂模式(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())
    
    # 原图层数据随着浅复制图层数据的修改而修改,深复制图层数据不受影响
Share on

Qfrost
WRITTEN BY
Qfrost
CTFer, Anti-Cheater, LLVM Committer