模板方法模式
python
复制代码
"""
案例:写简历
内容:
最近有个招聘会,可以带上简历去应聘了。
但是,其中有一家公司不接受简历,
而是给应聘者发了两张公司自己定制的简历表,分别是A类型的简历表和B类型的简历表
这两张表上面都有差不多的内容:基本信息、教育背景、工作经历,
让应聘者选择其中一种类型的简历表,按照要求填写完整。
每个人拿到这份表格后,就开始填写。
如果用程序实现这个过程,该如何做呢?
一种方案就是用模板方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。
模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
"""
from abc import ABC, abstractmethod
# 简历表(抽象类)
class ResumeTable(ABC):
@abstractmethod
def _write_basic_info(self): # 写基本信息(抽象)
pass
@abstractmethod
def _write_education(self): # 写教育背景(抽象)
pass
@abstractmethod
def _write_work_experience(self): # 写工作经历(抽象)
pass
# 填写简历的全过程(模板)
def fill_resume(self):
self._write_basic_info() # 先写基本信息
self._write_education() # 再写教育背景
self._write_work_experience() # 然后写工作经历
# A类型的简历表
class ResumeTableA(ResumeTable):
def _write_basic_info(self):
print("简历A: 基本信息, ", end="")
def _write_education(self):
print("教育背景, ", end="")
def _write_work_experience(self):
print("工作经验 (越简单越好).")
# B类型的简历表
class ResumeTableB(ResumeTable):
def _write_basic_info(self):
print("简历B: 基本信息, ", end="")
def _write_education(self):
print("教育背景, ", end="")
def _write_work_experience(self):
print("工作经验 (越详细越好).")
if __name__ == '__main__':
# 填写类型A的简历表
a = ResumeTableA()
a.fill_resume()
# 填写类型B的简历表
b = ResumeTableB()
b.fill_resume()
命令模式
python
复制代码
"""
案例:客人点餐
1. 客人发出命令,让厨师做饭
2. 客人发出命令,让厨师取消做饭
3. 客人发出命令,让厨师煮面
4. 客人发出命令,让厨师取消煮面
"""
from abc import ABC, abstractmethod
# 厨师(具体类)
class Chef: # 厨师有以下四种能力
# 做饭
def make_meals(self):
print("做饭")
# 取消做饭
def cancel_meals(self):
print("取消做饭")
# 煮面
def make_noodles(self):
print("煮面")
# 取消煮面
def cancel_noodles(self):
print("取消煮面")
# 命令(抽象类)
class Command(ABC):
def __init__(self):
self.__chef = None # 存放(维护)一个厨师对象
@abstractmethod
def execute_command(self): # 执行命令(抽象)
pass
@abstractmethod
def cancel_command(self): # 取消执行命令(抽象)
pass
# 关于做饭的命令(具体类)
class AboutMealsCommand(Command):
def __init__(self, chef: Chef):
super().__init__()
self.__chef = chef
def execute_command(self):
print("快点去给我", end="")
self.__chef.make_meals()
def cancel_command(self):
print("我不要了,", end="")
self.__chef.cancel_meals()
# 关于煮面的命令(具体类)
class AboutNoodlesCommand(Command):
def __init__(self, chef: Chef):
super().__init__()
self.__chef = chef
def execute_command(self):
print("快点去给我", end="")
self.__chef.make_noodles()
def cancel_command(self):
print("我不要了,", end="")
self.__chef.cancel_noodles()
# 客人(具体类)
class Customer:
# 客人想一些命令
def think_command(self, command: Command):
self.__command = command
# 客人说话(发出命令),说想要吃
def speak_to_eat(self):
self.__command.execute_command()
# 客人说话(发出命令),说不想吃了
def speak_to_cancel(self):
self.__command.cancel_command()
if __name__ == '__main__':
# 招聘一个厨师
chef = Chef()
# 与厨师约定好"做饭"和"煮面"相关的命令
about_meals_command = AboutMealsCommand(chef)
about_noodles_command = AboutNoodlesCommand(chef)
# 来了一位顾客
customer = Customer()
# 顾客思考一些关于煮饭的命令
customer.think_command(about_meals_command)
# 思考完毕,下达命令
customer.speak_to_eat() # 说自己想吃(饭)
customer.speak_to_cancel() # 说自己不想吃(饭)了
# 顾客思考一些关于煮面的命令
customer.think_command(about_noodles_command)
# 思考完毕,下达命令
customer.speak_to_eat() # 说自己想吃(面)
"""
运行结果:
快点去给我做饭
我不要了,取消做饭
快点去给我煮面
"""
责任链模式
python
复制代码
"""
案例:员工请假
内容:
当员工申请请假1天以内,由组长批准即可(处理者为组长)
当员工申请请假超过3天,需要由经理批准(处理者为经理)
当员工申请请假超过7天,需要由老板批准(处理者为老板)
"""
from abc import ABC, abstractmethod
# 处理者(抽象类)
class Handler(ABC):
def __init__(self):
self._next_handler = None # 用于存放下一个处理者
# 设置下一个处理者是谁
def set_next_handler(self, next_handler):
self._next_handler = next_handler
# 处理请求(先尝试自己的处理,如果处理不了,会将请求交给下一个处理者进行处理)
@abstractmethod
def handle_request(self, days):
pass
# 组长(具体类)
class GroupLeader(Handler):
def handle_request(self, days: int):
print("组长:", end="")
if days <= 3:
print("同意请假!")
else:
print("请假太久了,你去找经理请假。")
if self._next_handler:
self._next_handler.handle_request(days)
# 经理(具体类)
class Manager(Handler):
def handle_request(self, days: int):
print("经理:", end="")
if days <= 7:
print("同意请假!")
else:
print("请假太久了,你去找老板请假。")
if self._next_handler:
self._next_handler.handle_request(days)
# 老板(具体类)
class Boss(Handler):
def handle_request(self, days: int):
print("老板:", end="")
if days <= 10:
print("同意请假!")
else:
print("请假太久了,不同意请假")
if self._next_handler:
self._next_handler.handle_request(days)
if __name__ == '__main__':
# 实例化一个组长、一个经理、一个老板
group_leader = GroupLeader()
manager = Manager()
boss = Boss()
# 组装链
group_leader.set_next_handler(manager)
manager.set_next_handler(boss)
# -------------------- 请假 --------------------
day = 3
print(f"我:想要请假{day}天")
group_leader.handle_request(day)
print("-----------------------")
day = 7
print(f"我:想要请假{day}天")
group_leader.handle_request(day)
print("-----------------------")
day = 10
print(f"我:想要请假{day}天")
group_leader.handle_request(day)
print("-----------------------")
day = 30
print(f"我:想要请假{day}天")
group_leader.handle_request(day)
print("-----------------------")
策略模式
python
复制代码
from abc import ABC, abstractmethod
# 策略(抽象类)
class Strategy(ABC):
@abstractmethod
def execute(self, left: int, right: int): # 执行策略
pass
# 加法策略(具体类)
class AddStrategy(Strategy):
def execute(self, left: int, right: int):
return left + right
# 减法策略(具体类)
class SubStrategy(Strategy):
def execute(self, left: int, right: int):
return left - right
# 乘法策略(具体类)
class MulStrategy(Strategy):
def execute(self, left: int, right: int):
return left * right
# 除法策略(具体类)
class DivStrategy(Strategy):
def execute(self, left: int, right: int):
if right == 0:
raise "除数不能为零!"
return left / right
# 策略容器(具体类)
class Container:
def __init__(self):
self.__strategy = None # 用来保存(维护)一个策略对象
# 设置策略
def set_strategy(self, strategy: Strategy):
self.__strategy = strategy
# 执行某策略的功能
def execute_strategy(self, left: int, right: int):
return self.__strategy.execute(left, right)
if __name__ == '__main__':
# 实例化一个策略容器
container = Container()
# 符号处理的前期准备
symbol_list = ("+", "-", "*", "/") # 符号列表
index = 0 # 符号所在位置的索引(下标)
while True:
# 获取用户输入
expression = input("(Count) >>> ")
# 解析用户输入
# 1.符号处理(获取符号索引位置)
for symbol in symbol_list:
if symbol in expression: # 如果当前符号在表达式里面
index = expression.index(symbol) # 记录符号在表达式中的索引位置
break
# 2.获取左右值(例如 5 + 7 中的左值为5,右值为7)
left = int(expression[0: index: 1].strip())
right = int(expression[index + 1: len(expression): 1].strip())
# 3.根据用户选择,向策略容器里面添加合适的策略
match expression[index]:
case "+":
container.set_strategy(AddStrategy()) # 实例化一个策略,并添加到策略容器中
case "-":
container.set_strategy(SubStrategy()) # 实例化一个策略,并添加到策略容器中
case "*":
container.set_strategy(MulStrategy()) # 实例化一个策略,并添加到策略容器中
case "/":
container.set_strategy(DivStrategy()) # 实例化一个策略,并添加到策略容器中
case _:
raise "符号错误!"
# 4.执行策略容器里面的策略
print(container.execute_strategy(left, right))
观察者模式
python
复制代码
"""
案例:员工摸鱼
通过老板的动作信息(是否出现在公司),员工做出不同的反应(摸鱼或努力工作)
"""
from abc import ABC, abstractmethod
# 实现一个员工类(具体类)
class Employee:
def __init__(self, name):
self.__name = name # 存放员工自己的姓名
# 结合来自外部的通知信息,更新员工自己的工作状态(摸鱼或认真工作)
def update(self, info):
print(f"{self.__name}收到情报:{info},", end="")
if info == "老板来了":
print("开启工作模式。")
elif info == "老板走了":
print("开启摸鱼模式。")
# 实现一个老板类(具体类)
class Boss:
def __init__(self):
self.__employee_list = [] # 存放老板手下的员工对象
self.__action_plan = "" # 存放老板的行动计划
# 老板招聘员工
def add_employee(self, employee: Employee):
self.__employee_list.append(employee)
# 老板设置自己的行动计划
def set_action_plan(self, plan):
self.__action_plan = plan
self._notify(plan) # 泄密
# 发出通知
def _notify(self, plan):
# 根据老板的计划,设置泄密信息的内容
info = ""
if plan == "去巡查一下他们有没有好好工作":
info = "老板来了"
elif plan == "坐飞机出个差":
info = "老板走了"
# 通知每个员工
for employee in self.__employee_list:
employee.update(info)
if __name__ == '__main__':
# 实例化一个老板(被观察者)
boss = Boss()
# 实例化一些员工(观察者)
emp_1 = Employee("小明")
emp_2 = Employee("老张")
emp_3 = Employee("老李")
# 老板去招聘上面这些员工(建立关联)
boss.add_employee(emp_1)
boss.add_employee(emp_2)
boss.add_employee(emp_3)
# 老板设置行动计划
boss.set_action_plan("去巡查一下他们有没有好好工作")
print("-----------")
boss.set_action_plan("坐飞机出个差")
print("-----------")
访问者模式
python
复制代码
"""
案例:
这里实现一个不同职业的人去医院和餐厅的例子来说明访问者模式
在小镇上有一个医院和一个餐厅,
每天都会有不同的人访问这两个地方,
由于访问者不同到这两个地方要做的事也有区别。
医生去医院是为了工作给病人看病,
厨师去医院是为了检查身体,
医生去餐厅是为了吃饭,
厨师去餐厅是为了工作给客人烹饪菜肴。
"""
from abc import ABC, abstractmethod
# 地方(抽象类)
class Place(ABC):
def __init__(self, name: str):
self._place_name = name # 维护(存放)一个地方名字
@property
def name(self):
return self._place_name
@abstractmethod
def accept(self, visitor): # 接待访问者的功能(抽象)
pass
# 医院(具体类)
class Hospital(Place):
# 接待访问者的功能(实现)
def accept(self, visitor):
if visitor.__class__ is Doctor:
print(f"医院热情的接待他,因为他能帮助医院救人!")
elif visitor.__class__ is Chef:
print("医院快速的接待他,因为他来看病!")
# 餐馆(具体类)
class Restaurant(Place):
# 接待访问者的功能(实现)
def accept(self, visitor):
if visitor.__class__ is Doctor:
print(f"餐厅热情的接待他,因为他是顾客!")
elif visitor.__class__ is Chef:
print("餐厅快速的接待他,因为他要炒菜!")
# 访问者(抽象类)
class Visitor(ABC):
@abstractmethod
def visit(self, place): # 访问一个地方(抽象)
pass
# 医生(具体类)
class Doctor(Visitor):
# 访问一个地方的能力
def visit(self, place):
print(f"医生尝试访问{place.name},", end="")
place.accept(self) # 这个地方是否接收当前对象的访问
# 厨师(具体类)
class Chef(Visitor):
# 访问一个地方的能力
def visit(self, place):
print(f"厨师尝试访问{place.name},", end="")
place.accept(self) # 这个地方是否接收当前对象的访问
if __name__ == '__main__':
# 实例化一个医院
hospital = Hospital("蟒蛇市第一人民医院")
# 实例化一个餐馆
restaurant = Restaurant("幸福餐馆")
# 实例化一个医生(访问者)
doctor = Doctor()
# 实例化一个厨师(访问者)
chef = Chef()
# ------------------ 访问 ------------------
doctor.visit(hospital) # 医生访问医院
doctor.visit(restaurant) # 医生访问餐馆
chef.visit(hospital) # 厨师访问医院
chef.visit(restaurant) # 厨师访问餐馆
"""
运行结果:
医生尝试访问蟒蛇市第一人民医院,医院热情的接待他,因为他能帮助医院救人!
医生尝试访问幸福餐馆,餐厅热情的接待他,因为他是顾客!
厨师尝试访问蟒蛇市第一人民医院,医院快速的接待他,因为他来看病!
厨师尝试访问幸福餐馆,餐厅快速的接待他,因为他要炒菜!
"""
中介者模式
python
复制代码
from abc import ABC, abstractmethod
# 中介者(抽象类)
class Mediator(ABC):
def __init__(self):
self._hr = None
self._student = None
def set_hr(self, hr):
self._hr = hr
def set_student(self, student):
self._student = student
@abstractmethod
def match(self):
pass
# 角色(抽象类)
class Role(ABC):
def __init__(self, name: str, offer: str, mediator: Mediator):
self._name = name
self._offer = offer
self._mediator = mediator
@property
def name(self):
return self._name
@property
def offer(self):
return self._offer
@abstractmethod
def match(self, role): # 和哪个人进行匹配?
pass
# 学生(具体类)
class Student(Role):
def match(self, role):
self._mediator.set_student(self) # 在"中介"里面,设置好自己的学生信息
self._mediator.set_hr(role) # 在"中介"里面,设置好自己想要应聘的HR
self._mediator.match() # 设置完毕后,运行"中介"的匹配功能
# 人事HR(具体类)
class HR(Role):
def match(self, role):
self._mediator.set_hr(self) # 在"中介"里面,设置好自己的HR信息
self._mediator.set_student(role) # 在"中介"里面,设置好自己想要招聘的学生
self._mediator.match() # 设置完毕后,运行"中介"的匹配功能
# 猎聘App(具体类)
class LiePinApp(Mediator):
def match(self):
print("--------------- 欢迎使用猎聘App ---------------")
print(f"HR:{self._hr.name}\t|\t想要招聘:{self._hr.offer}")
print(f"学生:{self._student.name}\t|\t想要应聘:{self._student.offer}")
if self._hr.offer == self._student.offer:
print(">>> 配对成功")
else:
print(">>> 配对失败")
print("---------------------------------------------", end="\n\n")
if __name__ == '__main__':
# 实例化一个中介 ------------ 猎聘App
app = LiePinApp()
# 实例化一个HR
hr = HR("花儿姐", "软件工程师", app)
# 实例化两个学生
stu_1 = Student("小明", "软件工程师", app)
stu_2 = Student("小王", "硬件工程师", app)
# HR 通过 app 尝试匹配 stu_1
hr.match(stu_1)
hr.match(stu_2)
备忘录模式
python
复制代码
"""
备忘录模式:
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。
这样以后就可将该对象恢复到原先保存的状态。
案例:
比如我们打游戏时分,如果在打大BOSS之前存档,此时就需要将对应的游戏场景,任务信息,人物信息等等状态存储起来;
当赢得大BOSS之后,覆盖之前的存档时,就将之前的存档丢弃,新建立一个存档,保存当前的状态信息;
如果打输了,恢复存档,就将之前的存档信息读取出来,还原到打大BOSS之前的游戏场景,重新开始打大BOSS。
这里面就是使用的备忘录模式。
一个备忘录是一个对象,它存储另一个对象在某个瞬间的内部状态,而后者称为备忘录的原发器。
当需要设置原发器的检查点时,取消操作机制会向原发器请求一个备忘录。
原发器用描述当前状态的信息初始化该备忘录。
只有原发器可以向备忘录中存取信息,备忘录中的信息对其他的对象是"不可见"的。
"""
from abc import ABC, abstractmethod
# 备忘录(具体类)
class Memorandum:
def __init__(self, blood, attack, defense):
self.__blood = blood
self.__attack = attack
self.__defense = defense
@property
def blood(self):
return self.__blood
@property
def attack(self):
return self.__attack
@property
def defense(self):
return self.__defense
# 原发器:记录当前时刻的内部状态
class GameRole:
# 创建游戏角色时,默认的血量
def __init__(self, ):
self.__blood = 100
self.__attack = 100
self.__defense = 100
# 展示游戏角色的状态
def show_state(self):
print(f"当前角色:[生命力:{self.__blood}] [攻击力:{self.__attack}] [防御力:{self.__defense}]")
# 让游戏角色进行战斗
def fight(self):
self.__blood -= 40
self.__attack -= 16
self.__defense -= 32
print("遭受敌人攻击!生命力-40,攻击力-16,防御力-32...")
if self.__blood <= 0:
print("您已阵亡!")
# 存档:保存当前的数据到备忘录对象中
def save_state(self):
print("存档成功!")
return Memorandum(self.__blood, self.__attack, self.__defense)
# 恢复存档:从备忘录对象里面获取所需的数据
def recovery_state(self, memorandum: Memorandum):
self.__blood = memorandum.blood
self.__attack = memorandum.attack
self.__defense = memorandum.defense
print("恢复存档成功")
if __name__ == '__main__':
# 创建一个游戏角色
role = GameRole()
# 查看当前"游戏角色"的状态
role.show_state()
# 玩游戏(去战斗)
role.fight()
# 存档
record = role.save_state()
# 继续玩游戏(去战斗)
role.fight()
role.fight()
# 挑战Boss失败,就读档,恢复原来的状态
role.recovery_state(record)
# 继续玩游戏(去战斗)
role.fight()
状态模式
python
复制代码
from abc import ABC, abstractmethod
# 状态(抽象类)
class State(ABC):
@abstractmethod
def handle(self):
pass
# "None"状态类(具体类)
class NoneState(State):
def handle(self):
return "没有上下文..."
# "Exist"状态类(具体类)
class ExistState(State):
def handle(self):
return "存在上下文..."
# 上下文(具体类)
class Context:
def __init__(self, state: State):
self.__state = state # 存放一个状态对象
# 请求上下文
def request(self):
if self.__state:
print(f"内容:[{self.__state.handle()}]")
# 改变状态
def change_state(self, new_state):
self.__state = new_state
if __name__ == '__main__':
# 实例化两种状态
none_state = NoneState()
exist_state = ExistState()
# 实例化一个上下文
context = Context(none_state)
# 请求内容
context.request()
# 切换为 noneState 状态后,再次请求内容
context.change_state(exist_state)
context.request()
迭代器模式
python
复制代码
from abc import ABC, abstractmethod
# 简单迭代器(具体类)
class SimpleIterator:
# 初始化操作
def __init__(self, lst):
self.__lst = lst # 记录要被迭代的列表
self.__index = 0 # 记录当前迭代位置的索引(下标),初始化时,设置为0
# 重新定义 __iter__ ,防止用官方的 __iter__ 污染了自己要实现的迭代器
def __iter__(self):
return self
# 重新定义 __next__,实现自定义功能
def __next__(self):
if self.__index < len(self.__lst): # 索引(下标)合法
element = self.__lst[self.__index]
self.__index += 1
return element
else: # 索引(下标)不合法
raise StopIteration
if __name__ == '__main__':
my_list = [5, 4, 3, 2, 1]
my_iter = SimpleIterator(my_list)
try:
while True:
print(next(my_iter))
except StopIteration:
pass
解释器模式
python
复制代码
"""
实现原理:
原材料:
1.表达式(计算规则): a@b#c (需要解释成a+b-c的运算过程和结果)
2.数据对应关系(变量):
var_map = {
"a": 30,
"b": 20,
"c": 25
}
产品:
a@b#c ==》 变量解释器1 @ 变量解释器2 # 变量解释器3
==》 栈 【 => 变量解释器1 => 变量解释器2 => 变量解释器3 => 】 与 【=> @符号对象 => #符号对象】
"""
from abc import ABC, abstractmethod
# 解释器(抽象类)
class Interpreter(ABC):
@abstractmethod
def parse(self, var_map: dict): # 执行解析
pass
# 变量解释器(具体类)
# 一个变量解释器对象只能解释一个变量字符
class VarInterpreter(Interpreter):
def __init__(self, var: str):
self.__var = var # 用来记录待解析的变量字符
def parse(self, var_map: dict) -> int: # 函数返回值 int 类型
return var_map[self.__var]
# 运算符解释器
# 1.抽象父类
class SymbolInterpreter(Interpreter):
def __init__(self, left: VarInterpreter, right: VarInterpreter):
self._left = left # 用来记录"变量解释器对象"
self._right = right # 用来记录"变量解释器对象"
@property
def left(self): # 提供接口,让外界可以读取
return self._left
@property
def right(self): # 提供接口,让外界可以读取
return self._right
@abstractmethod
def parse(self, var_map: dict):
pass
# 2.具体子类
# 2.1 加法解释器(具体类)
class AddInterpreter(SymbolInterpreter):
def parse(self, var_map: dict) -> int:
return self._left.parse(var_map) + self._right.parse(var_map)
# 2.2 减法解释器(具体类)
class SubInterpreter(SymbolInterpreter):
def parse(self, var_map: dict) -> int:
return self._left.parse(var_map) - self._right.parse(var_map)
# 封装一个解析者类,统一调用上面的接口
class Parser:
def __init__(self, expression: str):
self.__final_interpreter = None # 存放(维护)一个最终解释器对象
interpreter_stack = [] # 自定义栈,用来临时存放"解释器对象"的栈
# 解析字符串 a@b#c
i = 0
while i < len(expression):
# ---------------- 循环要做的事情 -----------------
match expression[i]:
case "@": # 匹配到+这个符号,执行加法解释
# 从栈顶中读取解释器对象
left = interpreter_stack.pop()
# 从文法字符串中,构建解释器对象
right = VarInterpreter(expression[i + 1])
# 传入解释器对象,构建新的解释器对象,将其存入栈中
interpreter_stack.append(AddInterpreter(left, right))
# 因为 right 那里是提前构建了对象,所有我们需要跳过下一字符的匹配
i += 1
case "#": # 匹配到-这个符号,执行减法解释
# 从栈中取出解释器对象
left = interpreter_stack.pop()
# 从文法字符串中,构建解释器对象
right = VarInterpreter(expression[i + 1])
# 传入解释器对象,构建新的解释器对象,将其存入栈中
interpreter_stack.append(SubInterpreter(left, right))
# 因为 right 那里是提前构建了对象,所有我们需要跳过下一字符的匹配
i += 1
case _:
interpreter_stack.append(VarInterpreter(expression[i]))
# ---------------- 循环要做的事情 -----------------
i += 1 # 循环自增
# 保存最终解释对象
if interpreter_stack: # 如果栈不为空
self.__final_interpreter = interpreter_stack.pop() # 栈顶中保存的就是最终语法树的根
# 执行解析
def execute(self, var_map: dict) -> int:
# self.__final_interpreter.parse(var_map) 的调用过程有点类似于递归,可以自己画图分析
# 解析结果:
res = -1 if (self.__final_interpreter is None) else self.__final_interpreter.parse(var_map)
return res
if __name__ == '__main__':
# 要解析的表达式
expression = "a@b#c"
# 符号与数据之间的映射关系------------变量------------法则
var_map = {
"a": 30,
"b": 20,
"c": 25
}
# 实例化一个解析者,解析上面的表达式
parser = Parser(expression)
# 执行解释
res = parser.execute(var_map) # 30@20#25 == 30+20-25 == 25
print(res)