这篇文章讨论了享元模式与命令模式。
这是设计模式系列文章的一部分,点击查看该系列的其他文章。
享元模式
元、气之始,引申为元气。享元模式即共享最初的那部分,哪部分呢?
假设你有一个需求需要创建大量的类实例,利用享元模式,就可以保证共享同一状态的对象,可以同时使用该共享状态的内存。
举个例子,之前聊过的汽车销售系统。对于每一辆车,我们可以加装不同的配置,比如有尊享版、豪华版等等。
不同版本之间,其实是大同小异。
如果对于每辆车我们都去统计它有什么功能,没有什么功能,则会产生巨大的浪费。
我们可以通过共享对象去存储那些与型号相关的特性列表。
享元在 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
49import gc # 垃圾回收器
import weakref # 弱引用数据结构包
class CarModel:
"""弱引用的字典,内部的对象弱没有被引用,则会被回收。
"""
_models = weakref.WeakValueDictionary()
def __new__(cls, model_name, *avgs, **kvargs):
"""这里对新实例的创建自定义,与单例模式有点类似
"""
model = cls._models.get(model_name)
if not model:
model = super().__new__(cls)
cls._models[model_name] = model
return model
def __init__(self, model_name, air=False, title=False,
cruise_control=False, power_locks=False,
allow_whells=False, use_charger=False):
"""实例的初始化,在这里完成
"""
self.model_name = model_name
self.air = air
self.title = title
self.cruise_control = cruise_control
self.power_locks = power_locks
self.allow_whells = allow_whells
self.use_charger = use_charger
def check_serial(self, serial_number):
print(
"Sorry We are anble to check",
"the seria number {0} on the {1}",
"at this time".format(self.number, self.model_name)
)
class Car:
def __init__(self, model, color, serial):
self.model = model
self.color = color
self.serial = serial
def check_serial(self):
return self.model.check_serial(self.serial)
上面定义了两个类,一个是汽车模版,一个是汽车。我们来生产几辆车:
1 | dx = CarModel("FIT DX") |
现在来观察他们的内存地址:
1 | # display(id(lx)) -> 4402294352 |
享元模式使用起来比普通的类实现更负责,但如果你有成百上千的类实例需要创建的时候,享元模式可以极大的节省你的内存,可以说享元模式是专为节省内存而设计的。
命令模式
命令模式在必须被完成的行为和调用这些动作的对象之间添加了一个抽象层,这句话可能比较难理解,我们看一个例子。
这个模式在图形窗口中的操作中应用的比较多。
我们实现一个窗口程序,它有退出和保存的功能。
1 | import sys |
使用:
1 | # 新建一个窗口 |
还有一种更简洁、更 Python 的实现:
1 | import sys |
或者直接调用类,只需实现 __call__
方法即可:
1 | class SaveCommand: |