常用设计模式

设计模式大概分为 23 种,分三大类:

  • 创建型模式 (Creational Patterns)
  • 结构型模式 (Structural Patterns)
  • 行为型模式 (Behavioral Patterns)

创建型模式

创建型模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建那些对象时更加灵活。

  • 工厂模式 (Factory Pattern)
  • 抽象工厂模式 (Abstract Factory Pattern)
  • 单例模式 (Singleton Pattern)
  • 创建者模式 (Builder Pattern)
  • 原型模式 (Prototype Pattern)

简单工厂模式

简单工厂模式不是 23 种设计模式里的一种,一般用于小项目或具体产品很少扩展的情况。它由三种角色组成:

  • 抽象产品
  • 具体产品
  • 工厂类
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
from abc import ABCMeta, abstractmethod


class Car(metaclass=ABCMeta):
"""Abstract product."""
@abstractmethod
def price(self):
pass


class Bmw(Car):
"""Implemented product."""

def price(self):
return '$100,000'


class Byd(Car):
"""Implemented product"""

def price(self):
return '$10,000'


class Factory(object):
"""Factory"""
def produce(self, car_type):
if car_type == 'bmw':
return Bmw()
elif car_type == 'byd':
return Byd()
else:
return None


class Client(object):
def main(self, *args, **kws):

Factory().produce('bmw').prince()
# BYD car
Factory().produce('byd').prince()

简单工厂模式实现了产品类与客户端分离,但当用户需要添加更多产品的时候,就要修改工厂类的代码了,工厂类并不符合 OOP 开放封闭原则

工厂模式

意图:定义一个创建对象的接口,让其子类自己决定实例化哪个工厂类,工厂模式使其创建过程延迟到子类进行。
主要解决:接口选择的问题。
优点:扩展性高,符合开闭原则。
缺点:每增加一个产品,都要增加一个具体产品类和具体工厂类,使得系统中类的个数不断增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。
角色

  • 抽象产品类
  • 具体产品类
  • 抽象工厂类
  • 具体工厂类
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
import abc


class Car(classmeta=abc.ABCMeta):
@abc.abstractmethod
def price(self):
pass


class Bmw(Car):
def price(self):
return '$10,000'


class Byd(Car):
def price(self):
return '$1,000'


class Factory(classmeta=abc.ABCMeta):
@abc.abstractmethod
def produce(self):
pass


class BmwFactory(Factory):
def produce(self):
return Bmw()


class BydFactory(Factory):
def produce(self):
return Byd()


class Client(object):
def main(self, *args, **kws):

bmw = BmwFactory().produce()
# BYD car
byd = BydFactory().produce()

抽象工厂模式

意图:创建一系列相关或相互依赖产品 (产品族)。当系统中的产品有多于一个的产品族,而系统只消费其中某一族的产品的时候。
主要解决:接口选择的问题。
优点:当客户端需要使用某一产品族的产品的时候,直接调用具体产品类接口,使用非常方便。
缺点:产品族扩展相对麻烦。

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
import 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Python implement singleton with __new__
class Singleton(object):
def __new__(cls, *args, **kwargs):
if not hasattr(cls, '_instance'):
cls._instance = super(Singleton, cls).__new__(cls, *args, **kwargs)
return cls._instance


# Python implement singleton with metaclass
class SingletonBase(type):
def __init__(self, *args, **kwargs):
_instance = None
super().__init__(self, *args, **kwargs)

def __call__(self, *args, **kwargs):
if not self._instance:
self._instance = super().__call__(self, *args, **kwargs)
return self._instance


class Singleton(metaclass=SingletonBase):
pass

创造者模式

意图:将一个复杂的构建与其表示相分离,使得同样的构建过程可以创建不同的表示。
主要解决:在软件系统中,系统由若干部件组完,这些部件不变,但是组合方式经常变化。
何时使用:一些基本部件不变,但其组合经常变化的时候。
角色

  • 产品类
  • 抽象建造者
  • 具体建造者
  • 指挥者 (director)

优点

  • 客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品。
  • 每一个具体建造者都相对独立,而与其它的具体建造者无关,因此可以很方便地替换具体建造者或新增具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。
  • 可以更加精密地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
  • 增加新的具体建造者无需修改原有类库的代码,指挥者类针对抽象建造者类编程,而不是具体建造者类,符合依赖倒置原则。
    缺点
  • 产品之间差异性很大的情况:建造者模式所创建的产品类一般具有较多的共同点,其组成部分相似,如果产品之间的差异很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
  • 产品内部变化很复杂的情况:如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。
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
import abc


class Meal(object):
"""meal product class"""
food = None
drink = None


class MealBuilder(metaclass=abc.ABCMeta):
"""Abstract builder"""

def __init__(self):
self.meal = Meal()

@abc.abstractmethod
def add_food(self):
pass

@abc.abstractmethod
def add_drink(self):
pass

def get_meal(self):
return self.meal


class MealA(MealBuilder):
"""Implement builder"""

def add_food(self):
self.meal.food = 'childken burger'

def add_drink(self):
self.meal.drink = 'coke'


class MealB(MealBuilder):
"""Implement builder"""

def add_food(self):
self.meal.food = 'veg burger'

def add_drink(self):
self.meal.drink = 'pepsi'


class Waiter(object):
"""director"""
def create(self, meal):
meal.add_food()
meal.add_drink()
return meal.get_meal()


class Client(object):
def main(self):
# meal A
a = MealA()
meal_a = Waiter(a).get_meal()
# meal B
b = MealB()
meal_b = Waiter(b).get_meal()