Python的23种设计模式
-
[Python与设计模式--前言]
- [一 什么是设计模式]
- [二 为什么要有设计模式]
- [三 有那些设计模式]
- [创建类设计模式(5种)]
- [结构类设计模式(7种)]
- [行为类设计模式(11种)]
- [四 设计模式与架构,框架的关系]
- [1 软件框架与设计模式的关系]
- [2 软件架构与设计模式的关系]
-
1 单例模式
- 一、总线
- 二、单例模式
- 三、单例模式的优点和应用
- 单例模式的优点
- 单例模式的应用举例
- 四、单例模式的缺点
-
2 工厂类相关模式(占了两种)
- 一、快餐点餐系统
- 二、工厂模式、简单工厂模式、抽象工厂模式
- 三、工厂模式的优点和应用
- 四、工厂类模式的不足
-
3 建造者模式
- 一、快餐点餐系统
- 二、建造者模式
- 三、建造者模式的优点和使用场景
- 优点:
- 使用场景:
- 四、建造者模式的缺点
-
4 原型模式
- 一、图层
- 二、原型模式
- 三、原型模式的优点和使用场景
- 优点:
- 使用场景:
- 四、原型模式的缺点
-
5 代理模式
- 一、网络服务器配置白名单
- 二、代理模式
- 三、代理模式的优点和应用场景
- 优点:
- 应用场景:
- 四、代理模式的缺点
-
6 装饰器模式
- 一、快餐点餐系统
- 二、装饰器模式
- 三、装饰器模式的优点和应用场景
- 优点:
- 应用场景:
- 四、装饰器模式的缺点
-
7 适配器模式
- 一、外包人员系统兼容
- 二、适配器模式
- 三、适配器模式的优点和使用场景
- 优点:
- 应用场景:
- 四、适配器模式的缺点
-
8 门面模式
- 一、火警报警器(1)
- 二、门面模式
- 三、门面模式的优点和使用场景
- 优点:
- 使用场景:
- 四、门面模式的缺点
-
9 组合模式
- 一、公司结构组织
- 二、组合模式
- 三、组合模式的优点和使用场景
- 优点:
- 使用场景:
- 四、组合模式的缺点
-
10 享元模式
- 一、网上咖啡选购平台
- 二、享元模式
- 三、享元模式的优点和使用场景
- 优点:
- 使用场景:
- 四、享元模式的缺点
-
11 桥梁模式
- 一、画笔与形状
- 二、桥梁模式
- 三、桥梁模式的优点和应用场景
- 优点:
- 应用场景:
- 四、桥梁模式的缺点
-
12 策略模式
- 一、客户消息通知
- 二、策略模式
- 三、策略模式的优点和应用场景
- 优点:
- 应用场景:
- 四、策略模式的缺点
-
13 责任链模式
- 一、请假系统
- 二、责任链模式
- 三、责任链模式的优点和应用场景
- 优点:
- 应用场景:
- 四、责任链模式的缺点
-
14 命令模式
- 一、饭店点餐系统
- 二、命令模式
- 三、命令模式的优点和应用场景
- 优点:
- 应用场景:
- 四、命令模式的缺点
-
15 中介者模式
- 一、仓储管理系统
- 二、中介者模式
- 三、中介者模式的优点和应用场景
- 优点:
- 应用场景:
- 四、中介者模式的缺点
-
16 模板模式
- 一、股票查询客户端
- 二、模板模式
- 三、模板模式的优点和应用
- 优点:
- 使用场景:
- 四、模板模式的缺点
-
17 迭代器模式
- 一、迭代器与生成器
- 二、迭代器模式
-
18 访问者模式
- 一、药房业务系统
- 二、访问者模式
- 三、访问者模式的优点和应用场景
- 优点:
- 应用场景:
- 四、访问者模式的缺点
-
19 观察者模式
- 一、火警报警器
- 二、观察者模式
- 三、观察者模式的优点和应用场景
- 优点:
- 应用场景:
- 四、观察者模式的缺点
-
20 解释器模式
- 一、模拟吉他
- 二、解释器模式
- 三、解释器模式的优点和应用场景
- 优点:
- 应用场景:
- 四、解释器模式的缺点
-
21 备忘录模式
- 一、游戏进度保存
- 二、备忘录模式
- 三、备忘录模式应用场景
-
22 状态模式
- 一、电梯控制器
- 二、状态模式
- 三、状态模式的优点和应用场景
- 优点:
- 应用场景:
- 四、状态模式的缺点
-
23 设计原则
- 一 六大设计原则
- 1、单一职责原则
- 2、里氏替换原则
- 3、依赖倒置原则
- 4、接口隔离原则
- 5、迪米特法则(最少知识原则)
- 6、开闭原则
- 二 遵循设计原则的好处
- 三、设计原则与设计模式
- 1、创建类设计模式与设计原则
- 2、结构类设计模式与设计原则
- 3、行为类设计模式与设计原则
1 单例模式
8 门面模式
假设有一组火警报警系统,由三个子元件构成:一个警报器,一个喷水器,一个自动拨打电话的装置。其抽象如下:
class AlarmSensor:
def run(self):
print("Alarm Ring...")
class WaterSprinker:
def run(self):
print("Spray Water...")
class EmergencyDialer:
def run(self):
print("Dial 119...")
在业务中如果需要将三个部件启动,例如,如果有一个烟雾传感器,检测到了烟雾。在业务环境中需要做如下操作:
if __name__=="__main__":
alarm_sensor=AlarmSensor()
water_sprinker=WaterSprinker()
emergency_dialer=EmergencyDialer()
alarm_sensor.run()
water_sprinker.run()
emergency_dialer.run()
但如果在多个业务场景中需要启动三个部件,怎么办?Ctrl+C加上Ctrl+V么?当然可以这样,但作为码农的基本修养之一,减少重复代码是应该会被很轻易想到的方法。这样,需要将其进行封装,在设计模式中,被封装成的新对象,叫做门面。门面构建如下:
class EmergencyFacade:
def __init__(self):
self.alarm_sensor=AlarmSensor()
self.water_sprinker=WaterSprinker()
self.emergency_dialer=EmergencyDialer()
def runAll(self):
self.alarm_sensor.run()
self.water_sprinker.run()
self.emergency_dialer.run()
这样,业务场景中这样写就可以了:
if __name__=="__main__":
emergency_facade=EmergencyFacade()
emergency_facade.runAll()
二、门面模式
门面模式也叫外观模式,定义如下:要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。门面模式注重“统一的对象”,也就是提供一个访问子系统的接口。门面模式与之前说过的模板模式有类似的地方,都是对一些需要重复方法的封装。但从本质上来说,是不同的。模板模式是对类本身的方法的封装,其被封装的方法也可以单独使用;而门面模式,是对子系统的封装,其被封装的接口理论上是不会被单独提出来用的。
图片.png
三、门面模式的优点和使用场景
-
优点:
1、减少了系统之间的相互依赖,提高了系统的灵活;2、提高了整体系统的安全性:封装起的系统对外的接口才可以用,隐藏了很多内部接口细节,若方法不允许使用,则在门面中可以进行灵活控制。 -
使用场景:
1、为一个复杂的子系统提供一个外界访问的接口。这类例子是生活还是蛮常见的,例如电视遥控器的抽象模型,电信运营商的用户交互设备等;2、需要简化操作界面时。例如常见的扁平化系统操作界面等,在生活中和工业中都很常见。
四、门面模式的缺点
1、门面模式的缺点在于,不符合开闭原则,一旦系统成形后需要修改,几乎只能重写门面代码,这比继承或者覆写等方式,或者其它一些符合开闭原则的模式风险都会大一些。
19 观察者模式
一、火警报警器
在门面模式中,我们提到过火警报警器。在当时,我们关注的是通过封装减少代码重复。而今天,我们将从业务流程的实现角度,来再次实现该火警报警器。
class AlarmSensor:
def run(self):
print("Alarm Ring...")
class WaterSprinker:
def run(self):
print("Spray Water...")
class EmergencyDialer:
def run(self):
print("Dial 119...")
以上是门面模式中的三个传感器类的结构。仔细分析业务,报警器、洒水器、拨号器都是“观察”烟雾传感器的情况来做反应的。因而,他们三个都是观察者,而烟雾传感器则是被观察对象了。根据分析,将三个类提取共性,泛化出“观察者”类,并构造被观察者。观察者如下:
class Observer:
def update(self):
pass
class AlarmSensor(Observer):
def update(self,action):
print("Alarm Got: %s" % action)
self.runAlarm()
def runAlarm(self):
print("Alarm Ring...")
class WaterSprinker(Observer):
def update(self,action):
print("Sprinker Got: %s" % action)
self.runSprinker()
def runSprinker(self):
print("Spray Water...")
class EmergencyDialer(Observer):
def update(self,action):
print("Dialer Got: %s"%action)
self.runDialer()
def runDialer(self):
print("Dial 119...")
观察者中定义了update接口,如果被观察者状态比较多,或者每个具体的观察者方法比较多,可以通过update传参数进行更丰富的控制。下面构造被观察者。
class Observed:
observers=[]
action=""
def addObserver(self,observer):
self.observers.append(observer)
def notifyAll(self):
for obs in self.observers:
obs.update(self.action)
class smokeSensor(Observed):
def setAction(self,action):
self.action=action
def isFire(self):
return True
被观察者中首先将观察对象加入到观察者数组中,若发生情况,则通过notifyAll通知各观察者。业务代码如下:
if __name__=="__main__":
alarm=AlarmSensor()
sprinker=WaterSprinker()
dialer=EmergencyDialer()
smoke_sensor=smokeSensor()
smoke_sensor.addObserver(alarm)
smoke_sensor.addObserver(sprinker)
smoke_sensor.addObserver(dialer)
if smoke_sensor.isFire():
smoke_sensor.setAction("On Fire!")
smoke_sensor.notifyAll()
二、观察者模式
观察者模式也叫发布-订阅模式,其定义如下:定义对象间一种一对多的依赖关系,使得当该对象状态改变时,所有依赖于它的对象都会得到通知,并被自动更新。观察者模式的通知方式可以通过直接调用等同步方式实现(如函数调用,HTTP接口调用等),也可以通过消息队列异步调用(同步调用指被观察者发布消息后,必须等所有观察者响应结束后才可以进行接下来的操作;异步调用指被观察者发布消息后,即可进行接下来的操作。)。事实上,许多开源的消息队列就直接支持发布-订阅模式,如ZeroMQ等。
图片.png
三、观察者模式的优点和应用场景
- 优点:
1、观察者与被观察者之间是抽象耦合的;2、可以将许多符合单一职责原则的模块进行触发,也可以很方便地实现广播。 - 应用场景:
1、消息交换场景。如上述说到的消息队列等;2、多级触发场景。比如支持中断模式的场景中,一个中断即会引发一连串反应,就可以使用观察者模式。
四、观察者模式的缺点
1、观察者模式可能会带来整体系统效率的浪费;2、如果被观察者之间有依赖关系,其逻辑关系的梳理需要费些心思。