Python设计模式-行为型:策略模式,观察者模式,命令模式,模板方法
Python设计模式-行为型:策略模式,观察者模式,命令模式,模板方法
行为型模式会涉及到算法和对象间的职责分配,不仅描述对象或类的模式,还描述它们之间的通信方式,刻划了运行时难以跟踪的复杂的控制流,它们将你的注意力从控制流转移到对象间的关系上来。
- 策略模式定义及简单实现案例
- 观察者模式定义及简单实现案例
- 命令模式定义及简单实现案例
- 模板方法模式定义及简单实现案例
策略模式 strategy
case:一个问题可能有多种显示方式。如果用户有管理权限,那么问题的详情页面可能会显示编辑按钮,如果是普通用户则只显示问题内容。这样一个对象我们该怎么实现呢
# -*- coding: utf-8 -*-
class Question(object):
"""
问题对象,没有使用策略模式之前的作法
"""
def __init__(self, admin=True):
self._admin = admin
def show(self):
"""
根据是否是管理员显示不同的信息
"""
if self._admin is True:
return "show page with admin"
else:
return "show page with user"
if __name__ == '__main__':
q = Question(admin=False)
print(q.show())
以上代码中,最重要的操作就是Question.show操作,它会根据Quesiton._admin标志的不同完成两种显示。
现在我们有一些新的需求,增加Question的显示方式,怎么办?
- 如果增加更多的显示方式,按照以上作法,我们必然要修改Quesiton.show方法,并增加更多的标志位。
- 这样一来Question在面对不断增加的显示需求时都需要修改其代码,显然这是一种不好的设计。
下面该轮到策略模式发挥作用的时候了,策略模式将各种操作(算法)进行封装,并使它们之间可以互换。互换的意思是说可以动态改变对象的操作方式(算法)。
# -*- coding: utf-8 -*-
import abc
class AbsShow(object):
"""
抽象显示对象
"""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def show(self):
pass
class AdminShow(AbsShow):
"""
管理员的显示操作
"""
def show(self):
return "show with admin"
class UserShow(AbsShow):
"""
普通用户的显示操作
"""
def show(self):
return "show with user"
class Question(object):
"""
问题对象,使用策略模式之后的作法
"""
def __init__(self, show_obj):
self.show_obj = show_obj
def show(self):
return self.show_obj.show()
if __name__ == '__main__':
q = Question(show_obj=AdminShow())
print(q.show())
# 替换原来的显示对象,体现了策略模式的互换行为
q.show_obj = UserShow()
print(q.show())
将 Question 对象和显示方法进行了解耦,增加新的显示方法时,只需要增加新的显示对象就可以了。同时,在代码中还可以看到我们可以动态改变 Question 的显示方式,这也体现了策略模式的互换行为。
观察者模式 Observer
所谓观察者模式,就是说当一个对象发生变化时,观察者能及时得到通知并更新
# -*- coding: utf-8 -*-
import abc
class Subject(object):
"""
被观察对象的基类
"""
def __init__(self):
self._observers = []
def attach(self, observer):
"""
注册一个观察者
"""
if observer not in self._observers:
self._observers.append(observer)
def detach(self, observer):
"""
注销一个观察者
"""
try:
self._observers.remove(observer)
except ValueError:
pass
def notify(self):
"""
通知所有观察者,执行观察者的更新方法
"""
for observer in self._observers:
observer.update(self)
class Course(Subject):
"""
课程对象,被观察的对象
"""
def __init__(self):
super(Course, self).__init__()
self._message = None
@property
def message(self):
"""
message 是一个属性
"""
return self._message
@message.setter
def message(self, msg):
"""
message 属性设置器
"""
self._message = msg
self.notify()
class Observer(object):
"""
观察者抽象类
"""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def update(self, subject):
pass
class UserObserver(Observer):
"""
用户观察者
"""
def update(self, subject):
print("User observer: %s" % subject.message)
class OrgObserver(Observer):
"""
机构观察者
"""
def update(self, subject):
print("Organization observer: %s" % subject.message)
if __name__ == '__main__':
# 初始化一个用户观察者
user = UserObserver()
# 初始化一个机构观察者
org = OrgObserver()
# 初始化一个课程
course = Course()
# 注册观察者
course.attach(user)
course.attach(org)
# 设置course.message,这时观察者会收到通知
course.message = "two observers"
# 注销一个观察者
course.detach(user)
course.message = "single observer"
- Subject类,它实现了观察者模式中大部分功能。
- 作为一个被观察的对象,Subject实现了注册观察者,注销观察者和通知观察者的功能。
- 接着我们基于Subject创建了我们的课程Course类,并且当我们设置Course.message属性时,Course对象会通知到所有观察者。
- 可以看出,观察者模式使被观察的对象(主题)和观察者之间解耦了
命令模式 Command
命令模式就是对命令的封装。
- 所谓封装命令,就是将一系列操作封装到命令类中,并且命令类只需要对外公开一个执行方法execute,调用此命令的对象只需要执行命令的execute方法就可以完成所有的操作。
- 这样调用此命令的对象就和命令具体操作之间解耦了。
- 更进一步,通过命令模式我们可以抽象出调用者,接收者和命令三个对象。
- 调用者就是简单的调用命令,然后将命令发送给接收者,而接收者则接收并执行命令,执行命令的方式也是简单的调用命令的execute方法就可以了。
- 发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求
# -*- coding: utf-8 -*-
import abc
class VmReceiver(object):
"""
命令接收者,真正执行命令的地方
"""
def start(self):
print("Virtual machine start")
def stop(self):
print("Virtual machine stop")
class Command(object):
"""
命令抽象类
"""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def execute(self):
"""
命令对象对外只提供 execute 方法
"""
pass
class StartVmCommand(Command):
"""
开启虚拟机的命令
"""
def __init__(self, recevier):
"""
使用一个命令接收者初始化
"""
self.recevier = recevier
def execute(self):
"""
真正执行命令的时候命令接收者开启虚拟机
"""
self.recevier.start()
class StopVmCommand(Command):
"""
停止虚拟机的命令
"""
def __init__(self, recevier):
"""
使用一个命令接收者初始化
"""
self.recevier = recevier
def execute(self):
"""
真正执行命令的时候命令接收者关闭虚拟机
"""
self.recevier.stop()
class ClientInvoker(object):
"""
命令调用者
"""
def __init__(self, command):
self.command = command
def do(self):
self.command.execute()
if __name__ == '__main__':
recevier = VmReceiver()
start_command = StartVmCommand(recevier)
# 命令调用者同时也是客户端,通过命令实例也执行真正的操作
client = ClientInvoker(start_command)
client.do()
# 能告诉命令接收者执行不同的操作
stop_command = StopVmCommand(recevier)
client.command = stop_command
client.do()
命令模式的封装性很好:每个命令都被封装起来,对于客户端来说,需要什么功能就去调用相应的命令,而无需知道命令具体是怎么执行的。同时命令模式的扩展性很好,在命令模式中,在接收者类中一般会对操作进行最基本的封装,命令类则通过对这些基本的操作进行二次封装,当增加新命令的时候,对命令类的编写一般不是从零开始的,有大量的接收者类可供调用,也有大量的命令类可供调用,代码的复用性很好
模板方法模式 template method
在模板方法模式中,我们先定义一个类模板,在这个类中,我们定义了各种操作的顺序(轮毂或者说是骨架),但是并不实现这些操作,这些操作由子类来操作。
# -*- coding: utf-8 -*-
import abc
class Fishing(object):
"""
钓鱼模板基类
"""
__metaclass__ = abc.ABCMeta
def finishing(self):
"""
钓鱼方法中,确定了要执行哪些操作才能钓鱼
"""
self.prepare_bait()
self.go_to_riverbank()
self.find_location()
print("start fishing")
@abc.abstractmethod
def prepare_bait(self):
pass
@abc.abstractmethod
def go_to_riverbank(self):
pass
@abc.abstractmethod
def find_location(self):
pass
class JohnFishing(Fishing):
"""
John 也想去钓鱼,它必须实现钓鱼三步骤
"""
def prepare_bait(self):
"""
从淘宝购买鱼饵
"""
print("John: buy bait from Taobao")
def go_to_riverbank(self):
"""
开车去钓鱼
"""
print("John: to river by driving")
def find_location(self):
"""
在岛上选择钓点
"""
print("John: select location on the island")
class SimonFishing(Fishing):
"""
Simon 也想去钓鱼,它也必须实现钓鱼三步骤
"""
def prepare_bait(self):
"""
从京东购买鱼饵
"""
print("Simon: buy bait from JD")
def go_to_riverbank(self):
"""
骑自行车去钓鱼
"""
print("Simon: to river by biking")
def find_location(self):
"""
在河边选择钓点
"""
print("Simon: select location on the riverbank")
if __name__ == '__main__':
# John 去钓鱼
f = JohnFishing()
f.finishing()
# Simon 去钓鱼
f = SimonFishing()
f.finishing()
模板方法模式是结构最简单的行为型设计模式,在其结构中只存在父类与子类之间的继承关系。
- 通过使用模板方法模式,可以将一些复杂流程的实现步骤封装在一系列基本方法中,在抽象父类中提供一个称之为模板方法的方法来定义这些基本方法的执行次序,而通过其子类来覆盖某些步骤,从而使得相同的算法框架可以有不同的执行结果。
- 模板方法模式提供了一个模板方法来定义算法框架,而某些具体步骤的实现可以在其子类中完成
本文来自博客园,作者:OCEANEYES.GZY,转载请注明原文链接:https://www.cnblogs.com/oceaneyes-gzy/p/16462978.html
关于作者
👋 读书城南,🤔 在未来面前,我们都是孩子~
- 📙 一个热衷于探索学习新方向、新事物的智能产品经理,闲暇时间喜欢coding💻、画图🎨、音乐🎵、学习ing~
👋 Social Media
🛠️ Blog: http://oceaneyes.top
⚡ PM导航: https://pmhub.oceangzy.top
☘️ CNBLOG: https://www.cnblogs.com/oceaneyes-gzy/
🌱 AI PRJ自己部署的一些算法demo: http://ai.oceangzy.top/
📫 Email: 1450136519@qq.com
💬 WeChat: OCEANGZY
- 💬 公众号: UncleJoker-GZY
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步