Python 设计模式 (二)
09 代理模式
代理模式有3个必要的元素:
-
真实的对象
-
代理类
-
用户
代理模式存在在以下的情形中:
- 为真实目标类创建一个对象的代价是昂贵的,一个简单对象被代理类创建是便宜的方法。
- 对象必须防止被用户直接使用。
- 当实际请求的时候,为真实目标类创建一个对象会有延迟。
# -*- coding: utf-8 -*-
from abc import ABC, abstractmethod
# 支付接口
class Payment(ABC):
@abstractmethod
def do_pay(self):
pass
# 银行类:真实主题
class Bank(Payment):
def check_account(self):
print("账户检查中...")
return True
def do_pay(self):
self.check_account()
print("银行结算完成")
# 银行类的代理
class DebitCard(Payment):
def __init__(self):
self.bank = Bank()
def do_pay(self):
print("借记卡即将去银行支付")
self.bank.do_pay()
print("借记卡完成银行支付")
# 客户端
class You(object):
def __init__(self):
self.debit_card = DebitCard()
def make_payment(self):
print("借记卡支付开始")
self.debit_card.do_pay()
print("借记卡支付结束")
if __name__ == '__main__':
you = You()
you.make_payment()
"""
借记卡支付开始
借记卡即将去银行支付
账户检查中...
银行结算完成
借记卡完成银行支付
借记卡支付结束
"""
10 责任链模式
责任链模式 – 用于让多个对象处理一个请求时,或者用于预先不知道由哪个对象来处理某种特定请求时,其原则如下:
1、存在一个对象链(链表、树或者其他便捷的数据结构)。
2、一开始将请求发送给第一个对象,让其处理。
3、对象决定是否处理该请求。
4、对象将请求转发给下一个对象。
5、重复该过程,直到达到链尾。
需求
假设有这么一个请假系统:员工若想要请3天以内(包括3天的假),只需要直属经理批准就可以了;如果想请3-7天,不仅需要直属经理批准,部门经理需要最终批准;如果请假大于7天,不光要前两个经理批准,也需要总经理最终批准。类似的系统相信大家都遇到过,那么该如何实现呢?首先想到的当然是if…else…,但一旦遇到需求变动,其臃肿的代码和复杂的耦合缺点都显现出来。简单分析下需求,“假条”在三个经理间是单向传递关系,像一条链条一样,因而,我们可以用一条“链”把他们进行有序连接。
class Manager():
"""经理类"""
successor = None
name = ''
def __init__(self, name):
self.name = name
def setSuccessor(self, successor):
# 设置上级
self.successor = successor
def handleRequest(self, request):
# 处理请求
pass
class LineManager(Manager):
'''直属经理'''
def handleRequest(self, request):
if request.requestType == 'DaysOff' and request.number <= 3:
print( '%s:%s Num:%d Accepted OVER' % (
self.name, request.requestContent, request.number)
)
return "直属经理给假"
else:
print( '%s:%s Num:%d Accepted CONTINUE' % (
self.name, request.requestContent, request.number)
)
if self.successor != None:
return self.successor.handleRequest(request)
class DepartmentManager(Manager):
'''部门经理'''
def handleRequest(self, request):
if request.requestType == 'DaysOff' and request.number <= 7:
print( '%s:%s Num:%d Accepted OVER' % (
self.name, request.requestContent, request.number)
)
return "部门经理给假"
else:
print( '%s:%s Num:%d Accepted CONTINUE' % (
self.name, request.requestContent, request.number)
)
if self.successor != None:
return self.successor.handleRequest(request)
class GeneralManager(Manager):
'''总经理'''
def handleRequest(self, request):
if request.requestType == 'DaysOff':
print( '%s:%s Num:%d Accepted OVER' % (
self.name, request.requestContent, request.number)
)
return "总经理给假"
class Request():
def __init__(self, requestType ,requestContent, number = 0):
self.requestType = requestType
self.requestContent = requestContent
self.number = number
def commit(self,lineManager):
ret = lineManager.handleRequest(self)
print(ret)
return ret
if __name__=="__main__":
# 直属领导 部门领导 总经理
line_manager = LineManager('LINE MANAGER')
department_manager = DepartmentManager('DEPARTMENT MANAGER')
general_manager = GeneralManager('GENERAL MANAGER')
# 设置直属领导的上级为部门经理
line_manager.setSuccessor(department_manager)
# 设置上级领导的上级 为总经理
department_manager.setSuccessor(general_manager)
# 构建请求(请假) 使用commit 提交给直属领导
request = Request(requestContent="'Ask 1 day off'", requestType='DaysOff', number=1)
request.commit(line_manager)
request = Request(requestContent="'Ask 5 day off'", requestType='DaysOff', number=5)
request.commit(line_manager)
request = Request(requestContent="'Ask 10 day off'", requestType='DaysOff', number=9)
request.commit(line_manager)
分析:
1、有一个Request类,用来构建请求,同时调用commit方法提高到责任链的首段即 lineManager对象 来处理。
2、lineManager在处理该请求时,去校验是否为 请假类型和请假天数,若为请求天数 > 3天,则判断是否有上级,若有则调用上级即 departManager对象来处理。
3、部门领导如上,若请求天数 > 7天则提交给总经理 generalManager来处理,直到责任链的尾端。
4、责任链处理到尾端,则返回处理结果,当然该示例中没有结果返回。
该模式的优缺点:
优点:
1、将请求者与处理者分离,请求者并不知道请求是被哪个处理者所处理,易于扩展。
缺点:
1、如果责任链比较长,会有比较大的性能问题;
2、如果责任链比较长,若业务出现问题,比较难定位是哪个处理者的问题。
11 命令模式
import abc
class Receiver(object):
'''
命令接收者,正在执行命令的地方,实现了众多命令函数
'''
def start(self):
print('execute start command')
def stop(self):
print('execute stop command')
def suspend(self):
print('execute suspend command')
def play(self):
print('execute play command')
class Command(object):
"""
command抽象方法,子类必须要实现execute方法
"""
__metaclass__ = abc.ABCMeta
@abc.abstractmethod
def execute(self):
pass
class Start_command(Command):
"""
start命令类,对命令接收者类中start方法的封装
"""
def __init__(self, receiver):
self.receiver = receiver
def execute(self):
self.receiver.start()
class Stop_command(Command):
"""
stop命令类,对命令接收者类中stop方法的封装
"""
def __init__(self, receiver):
self.receiver = receiver
def execute(self):
self.receiver.stop()
class Client(object):
"""
调用命令的客户端
"""
def __init__(self, command):
self.command = command
def command_do(self):
self.command.execute()
if __name__ == '__main__':
receiver = Receiver()
start_command = Start_command(receiver)
client = Client(start_command)
client.command_do()
# 可以直接更换命令,如下,把start命令,换成stop命令
stop_command = Stop_command(receiver)
client.command = stop_command
client.command_do()
12 解释器模式
解释器模式(Interpreter Pattern)
给定一个语言并定义一个解释器,这个解释器使用该表示来解释语言中的句子.
# -*- coding:utf-8 -*-
# 定义语言类
class Code:
def __init__(self, text=None):
self.text = text
# 定义解释器 基类
class InterpreterBase:
def run(self, code):
pass
# 定义一个具体的解释器
class Interpreter(InterpreterBase):
def run(self, code):
code = code.text
code_dict = {'JAVA': "我是JAVA", "PYTHON": "我是python"}
print(code_dict.get(code))
if __name__ == '__main__':
# 初始化语言,并指定语言JAVA
test = Code()
test.text = 'JAVA'
# 运行
data1 = Interpreter().run(test)
# 指定语言为PYTHON
test.text = 'PYTHON'
data2 = Interpreter().run(test)
--------------------------------------------------
我是JAVA
我是python
13 观察者模式
我们希望一个对象发生变化的时候,另外一个或多个也会跟着变化
class Publisher: # 通知者
def __init__(self):
# 观察对象保存到这个列表中
self.observers = []
def add(self, observer):
# 使用add方法,添加观察对象
if observer not in self.observers:
self.observers.append(observer)
else:
print('Failed to add: {}'.format(observer))
def remove(self, observer):
# 使用 remove 删除观察对象
try:
self.observers.remove(observer)
except ValueError:
print('Failed to remove: {}'.format(observer))
def notify(self):
# notify()方法则在变化发生时通知所有观察者
[o.notify(self) for o in self.observers]
class DefaultFormatter(Publisher):
def __init__(self, name):
Publisher.__init__(self)
# 设置名字 和 初始数值
self.name = name
self._data = 0
def __str__(self):
return "{}: '{}' has data = {}".format(
type(self).__name__, self.name, self._data)
@property
def data(self):
return self._data
@data.setter
def data(self, new_value):
try:
self._data = int(new_value)
except ValueError as e:
print('Error: {}'.format(e))
else:
# 无异常发生 则执行此值
self.notify()
class HexFormatter: # 16进制
def notify(self, publisher):
print("{}: '{}' has now hex data = {}".format(
type(self).__name__, publisher.name, hex(publisher.data)))
class BinaryFormatter: # 2进制
def notify(self, publisher):
print("{}: '{}' has now bin data = {}".format(
type(self).__name__, publisher.name, bin(publisher.data)))
def main():
df = DefaultFormatter('test1')
print(df)
print()
hf = HexFormatter()
df.add(hf) # 添加16进制模式
df.data = 3 # 设置值为3,并处罚监视,打印的是add的,add多少打印多少
print(df) # 这个打印的是10进制
print()
bf = BinaryFormatter()
df.add(bf)
df.data = 21
print(df)
print()
df.remove(hf)
df.data = 40
print(df)
print()
df.remove(hf)
df.add(bf)
df.data = 'hello'
print(df)
print()
df.data = 15.8
print(df)
if __name__ == '__main__':
main()
DefaultFormatter: 'test1' has data = 0
HexFormatter: 'test1' has now hex data = 0x3
DefaultFormatter: 'test1' has data = 3
HexFormatter: 'test1' has now hex data = 0x15
BinaryFormatter: 'test1' has now bin data = 0b10101
DefaultFormatter: 'test1' has data = 21
BinaryFormatter: 'test1' has now bin data = 0b101000
DefaultFormatter: 'test1' has data = 40
Failed to remove: <__main__.HexFormatter object at 0x000001E7A04BD288>
Failed to add: <__main__.BinaryFormatter object at 0x000001E7A04BDA48>
Error: invalid literal for int() with base 10: 'hello'
DefaultFormatter: 'test1' has data = 40
BinaryFormatter: 'test1' has now bin data = 0b1111
DefaultFormatter: 'test1' has data = 15
14 状态模式
有一个判断条件,判断其
所在的状态
这个对象的状态判断可能过于复杂 ,我们把判断逻辑转移到不同的类当中
对象的行为会改变它的状态,并且在运行时,状态也可以改变行为。
# 状态基类
class State(object):
def __init__(self):
pass
def write_program(self, w):
pass
class Work(object):
def __init__(self):
self.hour = 9 #初始状态为上午9点
self.curr = ForenoonState() # 游标指向上午状态
def set_state(self, s): # s是各种状态类的实例
self.curr = s
def write_program(self): # 可以是看做刷新状态
self.curr.write_program(self)
# 运行游标的 write_program 方法
# 这里的 括号里的self 要特别注意,self 就是下面的w, 它是work的实例
# 实例 a ,调用 f方法 直接 a.f() 即可,我们传入self,是当前的实例
# 上午状态类
class ForenoonState(State):
def write_program(self, w):
#
if w.hour < 12:
print ("当前时间:%s点,"%w.hour,"精神百倍")
else:
w.set_state(AfternoonState())
w.write_program()
# 下午状态类
class AfternoonState(State):
def write_program(self, w):
if w.hour < 17:
print ("当前时间:%s点,"%w.hour,"状态还行,继续努力")
else:
w.set_state(EveningState())
w.write_program()
# 晚上状态类
class EveningState(State):
def write_program(self, w):
if w.hour < 21:
print ("当前时间:%s点,"%w.hour,"加班呢,疲劳了")
else:
w.set_state(SleepState())
w.write_program()
# 睡眠状态类
class SleepState(State):
def write_program(self, w):
print(type(w))
print("当前时间:%s点,"%w.hour,"不行了,睡着了")
if __name__=="__main__":
work = Work()
# 设置9点 刷新
work.hour = 9
work.write_program()
# 设置15点刷新
work.hour = 15
work.write_program()
# 设置20点
work.hour = 20
work.write_program()
# 设置22点
work.hour = 22
# 刷新
work.write_program()
15 策略模式 strategy
比如我们有两个算法, 有些时候会选择 f01
, 有些时候会选择f02
,根据需要选择。
def f01():
pass
def f02():
pass
def F(arg1,func):
data = func(arg1)
return data
if __name__ == "__main__"":
strategies = { "1" : f01, "2" : f02 } # 可选策略
strategy = strategies["1"] # 选择 名字叫 "1" 的策略
F(arg,strategy) # 调用
# KeyError 没有这个策略会报错 可以try捕捉
16 模板模式
感觉和策略模式差不多,当策略模式中 f0x 内有重复的时候,可以继续将相同的部分提取出来。
def nonmainstream_style(msg):# 非主流样式
msg = "****经过一番计算,得到非主流字体格式"
return msg
def template_style(msg):# 默认模板样式
msg = "****经过一番计算,得到默认字体格式"
return msg
def generate_style(msg,style=template_style): # 生产样式
print("start generate_style")
style(msg)
print("end of generate_style")
if __name__ == "__main__"":
result = generate_style("hello",style=nonmainstream_style)