常用设计模式
设计模式分类
设计模式大概分为 23 种,分三大类:
- 创建型模式 (Creational Patterns)
- 结构型模式 (Structural Patterns)
- 行为型模式 (Behavioral Patterns)
创建型模式
创建型模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建那些对象时更加灵活。
- 工厂模式 (Factory Pattern)
- 抽象工厂模式 (Abstract Factory Pattern)
- 单例模式 (Singleton Pattern)
- 创建者模式 (Builder Pattern)
- 原型模式 (Prototype Pattern)
简单工厂模式
简单工厂模式不是 23 种设计模式里的一种,一般用于小项目或具体产品很少扩展的情况。它由三种角色组成:
- 抽象产品
- 具体产品
- 工厂类
1 | from abc import ABCMeta, abstractmethod |
简单工厂模式实现了产品类与客户端分离,但当用户需要添加更多产品的时候,就要修改工厂类的代码了,工厂类并不符合 OOP 开放封闭原则。
工厂模式
意图:定义一个创建对象的接口,让其子类自己决定实例化哪个工厂类,工厂模式使其创建过程延迟到子类进行。
主要解决:接口选择的问题。
优点:扩展性高,符合开闭原则。
缺点:每增加一个产品,都要增加一个具体产品类和具体工厂类,使得系统中类的个数不断增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。
角色:
- 抽象产品类
- 具体产品类
- 抽象工厂类
- 具体工厂类
1 | import abc |
抽象工厂模式
意图:创建一系列相关或相互依赖产品 (产品族)。当系统中的产品有多于一个的产品族,而系统只消费其中某一族的产品的时候。
主要解决:接口选择的问题。
优点:当客户端需要使用某一产品族的产品的时候,直接调用具体产品类接口,使用非常方便。
缺点:产品族扩展相对麻烦。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
71import abc
class Mouse(metaclass=abc.ABCMeta):
@abc.abstractmethod
def price(self):
pass
class DellMouse(Mouse):
def price(self):
return '$10'
class HpMouse(Mouse):
def price(self):
return '$15'
class Keyboard(metaclass=abc.ABCMeta):
@abc.abstractmethod
def price(self):
pass
class DellKeyboard(Keyboard):
def price(self):
return '$100'
class HpKeyboard(Keyboard):
def price(self):
return '$150'
class Factory(metaclass=abc.ABCMeta):
@abc.abstractmethod
def create_mouse(self):
pass
@abc.abstractmethod
def create_keyboard(self):
class DellFactory(Factory):
def create_mouse(self):
return DellMouse()
def create_keyboard(self):
return DellKeyboard()
class HpFactory(Factory):
def create_mouse(self):
return HpMouse()
def create_keyboard(self):
return HpKeyboard()
class client(object):
def main(self):
# HP product
hp = HpFactory()
hp_mouse = hp.create_mouse()
hp_keyboard = hp.create_keyboard()
# Dell product
dell = DellFactory()
dell_mouse = dell.create_mouse()
dell_keyboard = dell.create_keyboard()
单例模式
意图:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
主要解决:一个全局使用的类频繁地创建与销毁。
优点:在内存中只有一个实例,减少了内存的开销,同时避免了对资源的多重占用 (如写 文件操作)。
缺点:没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎样实例化。
使用场景:
- 要求生产唯一序列号。
- WEB 中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。
- 创建的一个对象需要消耗的资源过多,比如 I/O 与数据库的连接等。
1 | # Python implement singleton with __new__ |
创造者模式
意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
主要解决:在软件系统中,系统由若干部件组完,这些部件不变,但是组合方式经常变化。
何时使用:一些基本部件不变,但其组合经常变化的时候。
角色:
- 产品类
- 抽象建造者
- 具体建造者
- 指挥者 (director)
优点:
- 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品。
- 每一个具体建造者都相对独立,而与其它的具体建造者无关,因此可以很方便地替换具体建造者或新增具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。
- 可以更加精密地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
- 增加新的具体建造者无需修改原有类库的代码,指挥者类针对抽象建造者类编程,而不是具体建造者类,符合依赖倒置原则。
缺点: - 产品之间差异性很大的情况:建造者模式所创建的产品类一般具有较多的共同点,其组成部分相似,如果产品之间的差异很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
- 产品内部变化很复杂的情况:如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
1 | import abc |