Python 设计模式 (二)

Python 设计模式 (二)

09 代理模式

代理模式有3个必要的元素:

  • 真实的对象

  • 代理类

  • 用户

代理模式存在在以下的情形中:

  1. 为真实目标类创建一个对象的代价是昂贵的,一个简单对象被代理类创建是便宜的方法。
  2. 对象必须防止被用户直接使用。
  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)
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:C马雯娟 返回首页