python常用设计模式

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
        @abstractmethod
        def pay(self,money):
            pass
    
    class 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):  # 专门的接口(陆地)
        @abstractmethod
        def walk(self):
            pass
    
    class WaterAnimal(metaclass=ABCMeta):  # 专门的接口(水上)
        @abstractmethod
        def swim(self):
            pass
    
    class SkyAnimal(metaclass=ABCMeta):  # 专门的接口(天上)
        @abstractmethod
        def fly(self):
            pass
    
    
    class 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, abstractmethod

class Payment(metaclass=ABCMeta):  # 抽象产品角色
    # abc: abstract class
    @abstractmethod
    def pay(self,money):
        pass

class Alipay(Payment):   # 具体产品角色
    def __init__(self, use_huabei=False):
        self.use_huabei = use_huabei

    def 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, abstractmethod

class Payment(metaclass=ABCMeta):   # 抽象产品角色
    # abc: abstract class
    @abstractmethod
    def pay(self,money):
        pass

class Alipay(Payment):   # 具体产品角色
    def __init__(self, use_huabei=False):
        self.use_huabei = use_huabei

    def 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):  # 抽象工厂角色
    @abstractmethod
    def creat_payment(self):
        pass

class 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):
    @abstractmethod
    def show_shell(self):
        pass

class CPU(metaclass=ABCMeta):
    @abstractmethod
    def show_cpu(self):
        pass

class OS(metaclass=ABCMeta):
    @abstractmethod
    def show_os(self):
        pass

# -------抽象工厂-------
class PhoneFactory(metaclass=ABCMeta):
    @abstractmethod
    def make_shell(self):
        pass
    @abstractmethod
    def make_cpu(self):
        pass
    @abstractmethod
    def 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 = cpu
        self.os = os
        self.shell = shell

    def 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, abstractmethod

class Player:   # 产品
    def __init__(self, face=None, body=None, arm=None, leg=None):
        self.face = face
        self.body = body
        self.arm = arm
        self.leg = leg
    def __str__(self):
        return "%s, %s, %s, %s" % (self.face, self.body,self.arm, self.leg)

class PlayerBuilder(metaclass=ABCMeta):  # 抽象建造者
    @abstractmethod
    def build_face(self):
        pass

    @abstractmethod
    def build_body(self):
        pass

    @abstractmethod
    def build_arm(self):
        pass

    @abstractmethod
    def 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._instance

class 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:
    pass

class B:
    def __init__(self):
        self.a = A()

代码示例:

# 适配器模式
from abc import ABCMeta, abstractmethod

class Payment(metaclass=ABCMeta):  # 目标接口
    # abc: abstract class
    @abstractmethod
    def pay(self,money):
        pass

class 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 = payment

    def 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, abstractmethod

class Shape(metaclass=ABCMeta):   # 抽象
    def __init__(self,color):
        self.color = color

    @abstractmethod
    def draw(self):
        pass

class Color(metaclass=ABCMeta):   # 实现者
    @abstractmethod
    def paint(self,shape):
        pass

class 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, abstractmethod

class Graphic(metaclass=ABCMeta):  # 抽象组件
    @abstractmethod
    def draw(self):
        pass

class Point(Graphic):   # 叶子组件
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __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 = p1
        self.p2 = p2

    def __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, abstractmethod

class Subject(metaclass=ABCMeta):  # 抽象实体
    @abstractmethod
    def get_content(self):
        pass

    @abstractmethod
    def set_content(self,content):
        pass

class RealSubject(Subject):   # 实体
    def __init__(self,filename):
        self.filename = filename
        f = open(filename, 'r')
        print("读取文件内容")
        self.content = f.read()
        f.close()

    def get_content(self):
        return self.content

    def set_content(self,content):
        f = open(self.filename, 'w')
        f.write(content)
        f.close()

# 虚代理:
class VirtualProxy(Subject):
    def __init__(self,filename):
        self.filename = filename
        self.subj = None

    def 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, abstractmethod

class Handler(metaclass=ABCMeta):   # 抽象处理者
    @abstractmethod
    def handle_leave(self,day):
        pass

class 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, abstractmethod

class Observer(metaclass=ABCMeta):  # 抽象观察者(订阅者)
    @abstractmethod
    def update(self, notice):   # 这里的notice参数是一个Notice类的对象
        pass

class 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 双下划线表示私有

    @property
    def company_info(self):
        return self.__company_info

    @company_info.setter
    def company_info(self,info):
        self.__company_info = info
        self.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 = None

    def 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, abstractmethod

class Strategy(metaclass=ABCMeta):   # 抽象策略
    @abstractmethod
    def execute(self,data):
        pass

class 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 = data
        self.strategy = strategy

    def set_strategy(self, strategy):   # 设置策略
        self.strategy = strategy

    def 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 sleep

class Window(metaclass=ABCMeta):   # 抽象类
    @abstractmethod
    def start(self):
        pass

    @abstractmethod
    def repaint(self):
        pass

    @abstractmethod
    def stop(self):
        pass

    def run(self):   # 模板方法
        self.start()
        while True:
            try:
                self.repaint()
                sleep(1)
            except KeyboardInterrupt:  # 发送一个程序中断的命令,把程序停掉
                break
        self.stop()

# client
class MyWindow(Window):   # 具体类
    def __init__(self,msg):
        self.msg = msg

    def 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)