python常用设计模式

  • 一、设计模式基础
    • 1. 基础知识
    • 2. 面向对象设计SOLID原则
    • 3. 设计模式分类
    • 4. 简单工厂模式(Simple Factory Pattern)
  • 二、创建型模式(5种)
      • 1. 工厂方法模式(Factory Pattern)
      • 2. 抽象工厂模式(Abstract Factory Pattern)
      • 3. 建造者模式(Builder Pattern)
      • 4. 单例模式(Singleton Pattern)
      • 5. 原型模式(Prototype Pattern)
    • 创建型模式小结
  • 三、结构型模式(7种)
    • 1. 适配器模式(Adapter Pattern)
    • 2. 桥模式(Bridge Pattern)
    • 3. 组合模式(Composite Pattern)
    • 4. 外观模式(Facade Pattern)
    • 5. 代理模式(Proxy Pattern)
    • 6. 装饰模式(Decorator Pattern)
    • 7. 享元模式(Flyweight Pattern)
  • 四、行为型模式(11种)
    • 1. 责任链模式(Chain of Responsibility Pattern)
    • 2. 观察者模式(Observer Pattern)
    • 3. 策略模式(Strategy Pattern)
    • 4. 模板方法模式(Template Pattern)

一、设计模式基础

1. 基础知识

  • 设计模式:对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。每一个设计模式系统地命名、解释和评价了面向对象系统中一个重要的和重复出现的设计。

  • 面向对象的三大特性:

    1. 封装

    2. 继承

    3. 多态

    这三大特性顺序不能错,因为他们之间不是并列关系而是递进关系。

  • 接口:若干抽象方法的集合。

    作用:限制实现接口的类必须按照接口给定的调用方式实现这些方法;对高层模块隐藏了类的内部实现。

    代码示例:

    # 接口方法一:
    # class Payment:
    #     def pay(self,money):
    #         raise NotImplementedError  # 抛出一个没有实现错误,要求继承Payment的类必须实现pay方法# 接口方法二:常用
    from abc import ABCMeta, abstractmethod
    class Payment(metaclass=ABCMeta):# abc: abstract class@abstractmethoddef pay(self,money):passclass Alipay(Payment):def pay(self, money):print('支付宝支付%d元' % money)class WechatPay(Payment):def pay(self,money):print('微信支付%d元' % money)# p = Alipay()
    p = WechatPay()
    p.pay(100)
    
  • 如果一个类里有抽象方法,那么该类就是一个抽象类。上述代码中Payment类有抽象方法def pay(),所以Payment是一个抽象类。

  • 上述代码的Alipay类和Wechat类就算底层代码,对类的调用p.pay(100)就属于高层代码(模块),如果有了接口进行限制,编写高层代码的人只需要读懂接口就可以正确调用函数,而不必把底层的每个类是如何实现的挨个看一遍。

2. 面向对象设计SOLID原则

  • 单一职责原则(Single Responsibility Principle):不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。

  • 开放封闭原则(Open Closed Principle):一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。

  • 里氏替换原则(Liskov Substitution Principle):所有引用父类的地方必须能透明地使用其子类的对象。

  • 接口隔离原则(Interface-Segregation Principles):使用多个专门的接口,而不使用单一的总接口,即客户端(高层模块)不应该依赖那些它不需要的接口。

    解释:设计模式中客户端的概念通常是指高层代码(模块),并不是网络通信server、client概念下的客户端。

  • 依赖倒置原则(Dependence Inversion Principle):高层模块不应该依赖底层模块,二者都应该依赖其抽象(即接口);抽象不应该依赖细节;细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程。

    解释:这样如果底层代码进行了改动,高层代码(模块)则不用随之改动。抽象就是上述代码的class Payment接口,细节就是class Alipay和class WechatPay,应该是先定义好接口,然后根据接口规则去实现细节;不能先写好细节,根据细节去定义接口。

    代码示例:

    # 接口隔离原则
    class LandAnimal(metaclass=ABCMeta):  # 专门的接口(陆地)@abstractmethoddef walk(self):passclass WaterAnimal(metaclass=ABCMeta):  # 专门的接口(水上)@abstractmethoddef swim(self):passclass SkyAnimal(metaclass=ABCMeta):  # 专门的接口(天上)@abstractmethoddef fly(self):passclass Tiger(LandAnimal):def walk(self):print("老虎走路")class Frog(LandAnimal,WaterAnimal):def walk(self):print("青蛙走路")def swim(self):print("青蛙游泳")
    

3. 设计模式分类

  • 创建型模式(5种):工厂方法模式、抽象工厂模式、创建者模式、原型模式、单例模式。
  • 结构型模式(7种):适配器模式、桥模式、组合模式、装饰模式、外观模式、享元模式、代理模式。
  • 行为型模式(11种):解释器模式、责任链模式、命令模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、访问者模式、模版方法模式。

4. 简单工厂模式(Simple Factory Pattern)

  • 简单工厂模式不属于23种设计模式。

  • 内容:不直接向客户端暴露对象创建的实现细节,而是通过一个工厂类来负责创建产品类的实例。

  • 角色:

    工厂角色(Creator)

    抽象产品角色(Product)

    具体产品角色(Concrete Product)

代码示例:

# 简单工厂模式
from abc import ABCMeta, abstractmethodclass Payment(metaclass=ABCMeta):  # 抽象产品角色# abc: abstract class@abstractmethoddef pay(self,money):passclass Alipay(Payment):   # 具体产品角色def __init__(self, use_huabei=False):self.use_huabei = use_huabeidef pay(self, money):if self.use_huabei:print('花呗支付%d元' % money)else:print('支付宝余额支付%d元' % money)class WechatPay(Payment):   # 具体产品角色def pay(self,money):print('微信支付%d元' % money)class PaymentFactor:   # 工厂角色def creat_payment(self,method):if method == 'alipay':return Alipay()elif method == 'wechat':return WechatPay()elif method == 'huabei':return Alipay(use_huabei=True)else:raise TypeError("No such payment named %s" % method)# client (高层代码模块)
pf = PaymentFactor()
p = pf.creat_payment('huabei')
p.pay(100)
  • 优点:

    1. 隐藏了对象创建的实现细节。
    2. 客户端client(高层模块)不需要修改代码。
  • 缺点:
    1. 违反了单一职责原则,将创建逻辑集中到一个工厂类里。
    2. 当添加新产品时,需要修改工厂类代码,违反了开放封闭原则。

二、创建型模式(5种)

1. 工厂方法模式(Factory Pattern)

  • 内容:定义一个用于创建对象的接口(工厂接口),让子类决定实例化哪一个产品类。

  • 角色:

    抽象工厂角色(Creator)

    具体工厂角色(Concrete Creator)

    抽象产品角色(Product)

    具体产品角色(Concrete Product)

代码示例:

# 工厂方法模式
from abc import ABCMeta, abstractmethodclass Payment(metaclass=ABCMeta):   # 抽象产品角色# abc: abstract class@abstractmethoddef pay(self,money):passclass Alipay(Payment):   # 具体产品角色def __init__(self, use_huabei=False):self.use_huabei = use_huabeidef pay(self, money):if self.use_huabei:print('花呗支付%d元' % money)else:print('支付宝余额支付%d元' % money)class WechatPay(Payment):   # 具体产品角色def pay(self,money):print('微信支付%d元' % money)class BankPay(Payment):   # 具体产品角色def pay(self,money):print('银行卡支付%d元' % money)class PaymentFactory(metaclass=ABCMeta):  # 抽象工厂角色@abstractmethoddef creat_payment(self):passclass AlipayFactory(PaymentFactory):   # 具体工厂角色def creat_payment(self):return Alipay()class WechatpayFactory(PaymentFactory):   # 具体工厂角色def creat_payment(self):return WechatPay()class HuabeiFactory(PaymentFactory):   # 具体工厂角色def creat_payment(self):return Alipay(use_huabei=True)class BankPayFactory(PaymentFactory):   # 具体工厂角色def creat_payment(self):return BankPay()# client (高层代码模块)
pf = HuabeiFactory()
p = pf.creat_payment()
p.pay(100)
  • 优点:

    1. 每个具体产品都对应一个具体工厂类,不需要修改工厂类代码。
    2. 隐藏了对象创建的实现细节。
  • 缺点:

    每增加一个具体产品类,就必须增加一个相应的具体工厂类。

2. 抽象工厂模式(Abstract Factory Pattern)

  • 内容:定义一个工厂类接口,让工厂子类来创建一系列相关或相互依赖的对象。

  • 例:生产一部手机,需要手机壳、CPU、操作系统三类对象进行组装,其中每类对象都有不同的种类。对每个具体工厂,分别生产一部手机所需要的三个对象。

  • 相比工厂方法模式,抽象工厂模式中的每个具体工厂都生产一套产品。

  • 角色:

    抽象工厂角色(Creator)

    具体工厂角色(Concrete Creator)

    抽象产品角色(Product)

    具体产品角色(Concrete Product)

    客户端(Client)

代码示例:

# 抽象工厂模式
from abc import ABCMeta, abstractmethod# ------抽象产品--------
class PhoneShell(metaclass=ABCMeta):@abstractmethoddef show_shell(self):passclass CPU(metaclass=ABCMeta):@abstractmethoddef show_cpu(self):passclass OS(metaclass=ABCMeta):@abstractmethoddef show_os(self):pass# -------抽象工厂-------
class PhoneFactory(metaclass=ABCMeta):@abstractmethoddef make_shell(self):pass@abstractmethoddef make_cpu(self):pass@abstractmethoddef make_os(self):pass# -------具体产品--------
class SmallShell(PhoneShell):def show_shell(self):print("普通手机小手机壳")class BigShell(PhoneShell):def show_shell(self):print("普通手机大手机壳")class AppleShell(PhoneShell):def show_shell(self):print("苹果手机壳")class SnapDragonCPU(CPU):def show_cpu(self):print("骁龙CPU")class MediaTekCPU(CPU):def show_cpu(self):print("联发科CPU")class AppleCPU(CPU):def show_cpu(self):print("Apple A13 CPU")class Android(OS):def show_os(self):print("Android系统")class IOS(OS):def show_os(self):print("IOS系统")# -------具体工厂--------
class MiFactory(PhoneFactory):def make_cpu(self):return SnapDragonCPU()def make_os(self):return Android()def make_shell(self):return BigShell()class HuaweiFactory(PhoneFactory):def make_cpu(self):return MediaTekCPU()def make_os(self):return Android()def make_shell(self):return SmallShell()class IPhoneFactory(PhoneFactory):def make_cpu(self):return AppleCPU()def make_os(self):return IOS()def make_shell(self):return AppleShell()# client (高层代码模块)
class Phone:def __init__(self,cpu,os,shell):self.cpu = cpuself.os = osself.shell = shelldef show_info(self):print("手机信息:")self.cpu.show_cpu()self.os.show_os()self.shell.show_shell()def make_phone(factory):cpu = factory.make_cpu()os = factory.make_os()shell = factory.make_shell()return Phone(cpu, os, shell)p1 = make_phone(IPhoneFactory())
p1.show_info()
  • 优点:

    1. 将客户端与类的具体实现相分离。
    2. 每个工厂创建了一个完整的产品系列,使得易于交换产品系列。
    3. 有利于产品的一致性(即产品之间的约束关系)。
  • 缺点:

    难以支持新种类的(抽象)产品。

3. 建造者模式(Builder Pattern)

  • 内容:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。下例中漂亮女孩和怪兽就是不同的表示,PlayerDirector就是同样的构建过程。

  • 角色:

    抽象建造者(Builder)

    具体建造者(Concrete Builder)

    指挥者(Director)

    产品(Product)

代码示例:

# 建造者模式
from abc import ABCMeta, abstractmethodclass Player:   # 产品def __init__(self, face=None, body=None, arm=None, leg=None):self.face = faceself.body = bodyself.arm = armself.leg = legdef __str__(self):return "%s, %s, %s, %s" % (self.face, self.body,self.arm, self.leg)class PlayerBuilder(metaclass=ABCMeta):  # 抽象建造者@abstractmethoddef build_face(self):pass@abstractmethoddef build_body(self):pass@abstractmethoddef build_arm(self):pass@abstractmethoddef build_leg(self):pass# 表示代码:
class SexyGirlBuilder(PlayerBuilder):   # 具体建造者def __init__(self):self.player = Player()def build_face(self):self.player.face = "漂亮脸蛋"def build_body(self):self.player.body = "好身材"def build_arm(self):self.player.arm = "漂亮胳膊"def build_leg(self):self.player.leg = "大长腿"# 表示代码:
class Monster(PlayerBuilder):   # 具体建造者def __init__(self):self.player = Player()def build_face(self):self.player.face = "怪兽脸"def build_body(self):self.player.body = "怪瘦身"def build_arm(self):self.player.arm = "长毛的胳膊"def build_leg(self):self.player.leg = "长毛的腿"# 构造代码:
class PlayerDirector:  # 指挥者:控制组装顺序 身子-脸-胳膊-腿def build_player(self, builder):builder.build_body()builder.build_face()builder.build_arm()builder.build_leg()return builder.player# client (高层代码模块)
builder = SexyGirlBuilder()
director = PlayerDirector()
p = director.build_player(builder)
print(p)
  • 建造者模式与抽象工厂模式相似,也用来创建复杂对象。主要区别是建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列的产品对象。

  • 优点:

    1. 隐藏了一个产品的内部结构和装配过程。
    2. 将构造代码与表示代码分开。
    3. 可以对构造过程进行更精细的控制。

4. 单例模式(Singleton Pattern)

  • 内容:保证一个类只有一个实例,并提供一个访问它的全局访问点。

  • 角色:

    单例(Singleton)

代码示例:

# 单例模式class Singleton:def __new__(cls, *args, **kwargs):  # 用于在__init__之前,给整个对象初始化if not hasattr(cls, "_instance"):  # 如果这个类没有_instance属性cls._instance = super(Singleton, cls).__new__(cls)  # 则调用父类(Object)的__new__方法创建return cls._instanceclass MyClass(Singleton):def __init__(self, a):self.a = a"""本句执行时,先执行Singleton类的__new__方法,发现没有_instance属性,则调用父类__new__方法
创建一个实例,返回MyClass._instance,接着执行MyClass类的__init__方法,赋值self.a = 10"""
a = MyClass(10)"""本句执行时,先执行Singleton类的__new__方法,发现有_instance属性,直接返回MyClass._instance,
接着执行MyClass类的__init__方法,赋值self.a = 20,把上面的10覆盖掉了"""
b = MyClass(20)print(a.a)  # 20
print(b.a)  # 20
print(id(a),id(b))  # 2327807218520 2327807218520
  • 优点:

    1. 对唯一实例的受控访问。

    2. 单例相当于全局变量,但防止了命名空间被污染。

      解释:全局变量定义了就占用一个变量名,后面都无法使用该变量名;而单例的变量名用完了可以重新实例化赋给一个新的变量名。

5. 原型模式(Prototype Pattern)

使用场景不多,略

创建型模式小结

  • 抽象工厂模式和建造者模式相比于简单工厂模式和工厂方法模式而言更灵活也更复杂。
  • 通常情况下,设计以简单工厂模式或工厂方法模式开始,当你发现设计需要更大的灵活性时,则向更复杂的设计模式演化。

三、结构型模式(7种)

1. 适配器模式(Adapter Pattern)

  • 内容:将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

  • 两种实现方式:

    类适配器:使用多继承

    对象适配器:使用组合

面向对象里的组合

# 组合:在一个类里放入另外一个类的对象
class A:passclass B:def __init__(self):self.a = A()

代码示例:

# 适配器模式
from abc import ABCMeta, abstractmethodclass Payment(metaclass=ABCMeta):  # 目标接口# abc: abstract class@abstractmethoddef pay(self,money):passclass Alipay(Payment):def pay(self, money):print('支付宝支付%d元' % money)class WechatPay(Payment):def pay(self,money):print('微信支付%d元' % money)class BankPay:   # 待适配的类def cost(self,money):print('银联支付%d元' % money)class ApplePay:   # 待适配的类def cost(self,money):print('苹果支付%d元' % money)# 类适配器(多继承):每一个想要适配的类都得写一个对应的类适配器
# class NewBankPay(Payment, BankPay):
#     def pay(self, money):
#         self.cost(money)# 对象适配器(组合):只用写一个适配器,就可以适配多个类
class PaymentAdapter(Payment):def __init__(self,payment):self.payment = paymentdef pay(self,money):self.payment.cost(money)p = PaymentAdapter(ApplePay())
p.pay(100)
  • 角色:

    目标接口(Target)

    待适配的类(Adaptee)

    适配器(Adapter)

  • 适用场景:

    1. 想使用一个已经存在的类,而它的接口不符合你的要求。
    2. (对象适配器)想使用一些已经存在的子类,但不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。

2. 桥模式(Bridge Pattern)

  • 内容:将一个事物的两个维度分离,使其都可以独立地变化。下例中的两个维度分别是形状和颜色。

  • 角色:

    抽象(Abstraction)

    细化抽象(RefinedAbstraction)

    实现者(Implementor)

    具体实现者(Concretelmplementor)

代码示例:

# 继承的方式:紧耦合,不易扩展
class Shape:pass
class Line(Shape):pass
class Rectangle(Shape):pass
class Circle(Shape):pass
class RedLine(Line):pass
class GreenLine(Line):pass
class BlueLine(Line):pass# 桥模式
# 组合的方式:松耦合,易于扩展
from abc import ABCMeta, abstractmethodclass Shape(metaclass=ABCMeta):   # 抽象def __init__(self,color):self.color = color@abstractmethoddef draw(self):passclass Color(metaclass=ABCMeta):   # 实现者@abstractmethoddef paint(self,shape):passclass Rectangle(Shape):   # 细化抽象name = "长方形"def draw(self):# 长方形的逻辑self.color.paint(self)class Circle(Shape):   # 细化抽象name = "圆形"def draw(self):# 圆形的逻辑self.color.paint(self)class Line(Shape):   # 细化抽象name = "直线"def draw(self):# 直线的逻辑self.color.paint(self)class Red(Color):   # 具体实现者def paint(self,shape):print("红色的%s" % shape.name)class Green(Color):   # 具体实现者def paint(self,shape):print("绿色的%s" % shape.name)class Blue(Color):   # 具体实现者def paint(self,shape):print("蓝色的%s" % shape.name)# client# 因为Rectangle类继承了Shape类,而Shape类的构造方法需要color参数,所以要在实例化时传一个color的对象Red()
shape = Rectangle(Red())
shape.draw()shape2 = Line(Blue())
shape2.draw()
  • 应用场景:

    当事物有两个维度上的表现,两个维度都可能扩展时。

  • 优点:

    1. 抽象和实现相分离。
    2. 优秀的扩展能力。

3. 组合模式(Composite Pattern)

  • 内容:将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

  • 角色:

    抽象组件(Component)

    叶子组件(Leaf)

    复合组件(Composite)

    客户端(Client)

代码示例:

# 组合模式
from abc import ABCMeta, abstractmethodclass Graphic(metaclass=ABCMeta):  # 抽象组件@abstractmethoddef draw(self):passclass Point(Graphic):   # 叶子组件def __init__(self, x, y):self.x = xself.y = ydef __str__(self):return "点(%s,%s)" % (self.x,self.y)def draw(self):print(str(self))  # 把自己通过__str__方法变成字符串再打印class Line(Graphic):   # 叶子组件def __init__(self, p1, p2):self.p1 = p1self.p2 = p2def __str__(self):return "线段[%s,%s]" % (self.p1,self.p2)def draw(self):print(str(self))class Picture(Graphic):   # 复合组件def __init__(self,iterable):self.children = []for g in iterable:self.add(g)def add(self,graphic):self.children.append(graphic)def draw(self):print("------复合图形------")for g in self.children:g.draw()print("------复合图形------")# client客户端
p1 = Point(2,3)
l1 = Line(Point(3,4),Point(6,7))
l2 = Line(Point(1,5),Point(2,8))
pic1 = Picture([p1,l1,l2])p2 = Point(4,4)
l3 = Line(Point(1,1),Point(0,0))
pic2 = Picture([p2,l3])pic = Picture([pic1,pic2])
pic.draw()
  • 适用场景:

    1. 表示对象的“部分-整体”层次结构(特别是结构是递归的)。
    2. 希望用户忽略组合对象与单个对象的不同,用户统一地使用组合结构中的所有对象。
  • 优点:
    1. 定义了包含基本对象和组合对象的类层次结构。
    2. 简化客户端代码,即客户端可以一致地使用组合对象和单个对象。
    3. 更容易增加新类型的组件。

4. 外观模式(Facade Pattern)

  • 内容:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

  • 角色:

    外观(facade)

    子系统类(subsystem classes)

代码示例:

# 外观模式class CPU:   # 子系统类def run(self):print("CPU开始运行")def stop(self):print("CPU停止运行")class Disk:   # 子系统类def run(self):print("硬盘开始工作")def stop(self):print("硬盘停止工作")class Memory:   # 子系统类def run(self):print("内存通电")def stop(self):print("内存通电")class Computer:   # 外观def __init__(self):self.cpu = CPU()self.disk = Disk()self.memory = Memory()def run(self):self.cpu.run()self.disk.run()self.memory.run()def stop(self):self.cpu.stop()self.disk.stop()self.memory.stop()# client
computer = Computer()
computer.run()
computer.stop()
  • 优点:

    1. 减少系统相互依赖。
    2. 提高了灵活性。
    3. 提高了安全性。

5. 代理模式(Proxy Pattern)

  • 内容:为其他对象提供一种代理以控制对这个对象的访问。

  • 应用场景:

    远程代理:为远程的对象提供代理。

    虚代理:根据需要创建很大的对象。例如浏览器的无图模式,就是一开始不加载图片,显示的是一个小方框(图片类的虚代理),有需要了点开才加载图片。

    保护代理:控制对原始对象的访问,用于对象有不同访问权限时。

  • 角色:

    抽象实体(Subject)

    实体(RealSubject)

    代理(Proxy)

代码示例:

# 代理模式
from abc import ABCMeta, abstractmethodclass Subject(metaclass=ABCMeta):  # 抽象实体@abstractmethoddef get_content(self):pass@abstractmethoddef set_content(self,content):passclass RealSubject(Subject):   # 实体def __init__(self,filename):self.filename = filenamef = open(filename, 'r')print("读取文件内容")self.content = f.read()f.close()def get_content(self):return self.contentdef set_content(self,content):f = open(self.filename, 'w')f.write(content)f.close()# 虚代理:
class VirtualProxy(Subject):def __init__(self,filename):self.filename = filenameself.subj = Nonedef get_content(self):if not self.subj:self.subj = RealSubject(self.filename)return self.subj.get_content()def set_content(self,content):if not subj:self.subj = RealSubject(self.filename)return self.subj.set_content(content)# 保护代理:
class ProtectedProxy(Subject):def __init__(self,filename):self.subj = RealSubject(filename)def get_content(self):return self.subj.get_content()def set_content(self,content):raise PermissionError("无写入权限")# client
# subj = RealSubject("test.txt")
# subj.get_content()# subj = VirtualProxy("test.txt")
subj = ProtectedProxy("test.txt")
print(subj.get_content())
subj.set_content('xxx')
  • 优点:

    1. 远程代理:可以隐藏对象位于远程地址空间的事实。
    2. 虚代理:可以进行优化,例如根据要求创建对象。
    3. 保护代理:允许在访问一个对象时有一些附加的内务处理。

6. 装饰模式(Decorator Pattern)

7. 享元模式(Flyweight Pattern)

四、行为型模式(11种)

1. 责任链模式(Chain of Responsibility Pattern)

  • 内容:使多个对象都有机会处理请求,从而避免请求得发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

  • 角色:

    抽象处理者(Handler)

    具体处理者(ConcreteHandler)

    客户端(Client)

代码示例:

# 责任链模式
from abc import ABCMeta, abstractmethodclass Handler(metaclass=ABCMeta):   # 抽象处理者@abstractmethoddef handle_leave(self,day):passclass GeneralManager(Handler):   # 具体处理者def handle_leave(self,day):if day <= 10:print("总经理准假%d天" % day)else:print("你还是辞职吧")class DepartmentManager(Handler):   # 具体处理者def __init__(self):self.next = GeneralManager()def handle_leave(self,day):if day <= 5:print("部门经理准假%d天" % day)else:print("部门经理职权不足")self.next.handle_leave(day)class ProjectDirector(Handler):   # 具体处理者def __init__(self):self.next = DepartmentManager()def handle_leave(self,day):if day <= 1:print("项目主管准假%d天" % day)else:print("项目主管职权不足")self.next.handle_leave(day)# client
day = 4
h = ProjectDirector()
h.handle_leave(day)
  • 适用场景:

    1. 有多个对象可以处理一个请求,哪个对象处理由运行时决定。

    2. 在不明确接收者的情况下,向多个对象中的一个提交一个请求。

  • 优点:

    降低耦合度:一个对象无需知道是其他哪一个对象处理其请求。

2. 观察者模式(Observer Pattern)

  • 内容:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。观察者模式又称“发布-订阅”模式。

  • 角色:

    抽象主题(Subject)

    具体主题(ConcreteSubject) ——发布者

    抽象观察者(Observer)

    具体观察者(ConcreteObserver) ——订阅者

代码示例:

# 观察者模式
from abc import ABCMeta, abstractmethodclass Observer(metaclass=ABCMeta):  # 抽象观察者(订阅者)@abstractmethoddef update(self, notice):   # 这里的notice参数是一个Notice类的对象passclass Notice:  # 抽象发布者def __init__(self):self.observers = []def attach(self,obs):self.observers.append(obs)def detach(self,obs):self.observers.remove(obs)def notify(self):   # 推送for obs in self.observers:obs.update(self)class StaffNotice(Notice):def __init__(self,company_info=None):super().__init__()  # 调用父类__init__函数声明observers属性self.__company_info = company_info  # __company_info 双下划线表示私有@propertydef company_info(self):return self.__company_info@company_info.setterdef company_info(self,info):self.__company_info = infoself.notify()  # 推送# obj = StaffNotice()
# print(obj.__company_info)  # 在类外无法访问私有成员# obj = StaffNotice("abc")
# obj.company_info = "xyz" # 直接跳到@company_info.setter 执行下面的函数
# print(obj.company_info)class Staff(Observer):def __init__(self):self.company_info = Nonedef update(self, notice):self.company_info = notice.company_info# client
notice = StaffNotice("初始公司信息")
s1 = Staff()
s2 = Staff()
notice.attach(s1)
notice.attach(s2)
notice.company_info = "公司今年业绩非常好,给大家发奖金!" # 手动修改company_info
print(s1.company_info)
print(s2.company_info)notice.detach(s2)
notice.company_info = "公司明天放假"
print(s1.company_info)
print(s2.company_info)
  • 适用场景:

    1. 当一个抽象模型有两方面,其中一个方面依赖于另一个方面。将这两者封装在独立对象中以使它们可以各自独立地改变和复用。
    2. 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变。
    3. 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之,你不希望这些对象是紧密耦合的。
  • 优点:
    1. 目标和观察者之间的抽象耦合最小。
    2. 支持广播通信。

3. 策略模式(Strategy Pattern)

  • 内容:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

  • 角色:

    抽象策略(Strategy)

    具体策略(ConcreteStrategy)

    上下文(Context)

代码示例:

# 策略模式
from abc import ABCMeta, abstractmethodclass Strategy(metaclass=ABCMeta):   # 抽象策略@abstractmethoddef execute(self,data):passclass FastStrategy(Strategy):   # 具体策略def execute(self,data):print("用较快的策略处理%s" % data)class SlowStrategy(Strategy):   # 具体策略def execute(self,data):print("用较慢的策略处理%s" % data)class Context:   # 上下文def __init__(self, strategy, data):self.data = dataself.strategy = strategydef set_strategy(self, strategy):   # 设置策略self.strategy = strategydef do_strategy(self):   # 执行策略self.strategy.execute(self.data)# client
data = "[...]"
s1 = FastStrategy()
s2 = SlowStrategy()
context = Context(s1,data)
context.do_strategy()
context.set_strategy(s2)
context.do_strategy()
  • 优点:

    1. 定义了一系列可重用的算法和行为。
    2. 消除了一些条件语句。
    3. 可以提供相同行为的不同实现。
  • 缺点:

    客户端client必须了解不同的策略。

4. 模板方法模式(Template Pattern)

  • 内容:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

  • 角色:

    抽象类(AbstractClass):定义抽象的原子操作(钩子操作),实现一个模板方法作为算法的骨架。

    具体类(ConcreteClass):实现原子操作。

代码示例:

# 模板方法模式
from abc import ABCMeta, abstractmethod
from time import sleepclass Window(metaclass=ABCMeta):   # 抽象类@abstractmethoddef start(self):pass@abstractmethoddef repaint(self):pass@abstractmethoddef stop(self):passdef run(self):   # 模板方法self.start()while True:try:self.repaint()sleep(1)except KeyboardInterrupt:  # 发送一个程序中断的命令,把程序停掉breakself.stop()# client
class MyWindow(Window):   # 具体类def __init__(self,msg):self.msg = msgdef start(self):print("窗口开始运行")def stop(self):print("窗口结束运行")def repaint(self):print(self.msg)MyWindow("hello...").run()
  • 适用场景:

    1. 一次性实现一个算法的不变的部分。
    2. 各个子类中的公共行为应该被提取出来并集中到一个公共父类中以避免代码重复。
    3. 控制子类扩展。

================================================================
参考文献:
https://www.cnblogs.com/alex3714/articles/5760582.html

本篇涉及代码见week19

python常用设计模式相关推荐

  1. Python常用设计模式—创建型模式

    文章目录 一.简单工厂模式 二.工厂方法模式 三.抽象工厂模式 四.建造者模型 五.单例模式 六.创建型模式概述 一.简单工厂模式 简单工厂模式不是23中设计模式中的,但是必须要知道.简单工厂模式不直 ...

  2. python做平面设计-Python系列干货之——Python与设计模式

    原标题:Python系列干货之--Python与设计模式 一.创建类设计模式 前言: 什么样的程序员是一个好的程序员?学会很多门编程语言,就是一个好的程序员了么?事实上,学会一门编程语言不是一件很难的 ...

  3. Spring常用设计模式--简单工厂模式

    本专栏内容参考自:咕泡学院Tom老师的<Spring5核心原理与30个类手写实战>,仅作个人学习记录使用,如有侵权,联系速删. 工厂模式的由来:   在现实生活中我们都知道,原始社会自给自 ...

  4. Python 常用的标准库以及第三方库有哪些?

    Python常用库大全,看看有没有你需要的. 环境管理 管理 Python 版本和环境的工具 p – 非常简单的交互式 python 版本管理工具. pyenv – 简单的 Python 版本管理工具 ...

  5. Python 常用的标准库以及第三方库

    作者:史豹 链接:https://www.zhihu.com/question/20501628/answer/223340838 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转载 ...

  6. Python常用库 - 【持续整理归档】

    Python常用库 - [持续整理归档],比较多,会逐步慢慢细化分类和扩从python常用库.(最后更新:2020-4-8) 为方便Python开发人员进行敏捷开发,高效的完成工作需求,耗时很久整理的 ...

  7. Python常用标准库之正则表达式

    Python常用标准库之正则表达式 1.re模块常用函数 1.1 匹配对象以及group()和groups()方法 1.2 match()与search():匹配单个目标 1.3 findall(): ...

  8. 干货丨Python常用的1000+库大盘点

    Python常用库 Chardet字符编码探测器,可以自动检测文本.网页.xml的编码. colorama主要用来给文本添加各种颜色,并且非常简单易用. Prettytable主要用于在终端或浏览器端 ...

  9. python常用代码大全-Python常用库大全

    Python常用库大全,看看有没有你需要的. 环境管理 管理 Python 版本和环境的工具 p – 非常简单的交互式 python 版本管理工具. pyenv – 简单的 Python 版本管理工具 ...

最新文章

  1. 在腾讯,如何做 Code Review?
  2. R语言数据包自带数据集之ISwR包的melanom数据集字段解释、数据导入实战
  3. 差分约束系统——建模与求解
  4. 学python不会英语怎么办_Python学习 英语不好怎么办?这里有官方中文文档你看不看...
  5. mysql ansi_ANSI模式下如何运行MySQL
  6. jq简单封装replaceAll
  7. 初识ABP vNext(3):vue对接ABP基本思路
  8. 工作81:图片间隙问题
  9. Python爬虫之pyppeteer的使用(爬虫、获取cookie、截屏插件、防爬绕过)
  10. 简历人才库系统_人才招聘简历的3种选择
  11. 如何把Sql Server2005 数据库转换成Access
  12. chrome插件开发入门-保姆级攻略
  13. Android 中this的用法
  14. TX2打开can0外设自启动
  15. 天翼云技术B卷编程题
  16. 电脑安全证书错误怎么处理比较好
  17. php,tp5关键词,分词模糊查询并根据查询条件排序
  18. 各种Android实现边框
  19. linux 文件的列数,Linux 输出文件列数,拼接文件
  20. 流体力学(水力学)满分实验报告——伯努利方程

热门文章

  1. 苹果home键在哪里设置_苹果手机隐藏的几个重要设置 你都知道吗?
  2. Hick 也八卦:CCTV 正式把李宇春列为男歌手
  3. 有了恒宇电脑的解决方案,一千多元电脑主机吃鸡无压力,解决你电脑配置的所有问题**
  4. python 漂亮界面demo_demo
  5. 家用计算机是数模混合,计算机可分为哪几类?依据是什么?
  6. 360n6能装原装android,降价之后,官方确认360 N6 Pro升级安卓8.0
  7. MySQL的50条经典语句(更新中...
  8. 十代服务器芯片组,英特尔十代酷睿处理器想用先换主板 AMD锐龙将继续碾压英特尔...
  9. 最近开启新一轮投稿。。
  10. 使用Flask搭建一个流媒体服务器