Design Pattern

设计模式

1、设计模式的定义

对软件设计中普遍存在(反复出现)的各种问题,所提出的解决方案。每一个设计模式系统地命名、解释和评价了面向对象系统中一个重要的和重复出现的设计。
就是为了解决面向对象系统中重要和重复的设计封装在一起的一种代码实现框架,可以使得代码更加易于扩展和调用。

  1. 时间复杂度: 第1种列表法的时间复杂度是O(n2).第2种链表法的时间复杂度是O(nm)
  2. 如果n大于m时,链表法优于列表法,n小于m时,列表法优于链表法

2、六大原则(SOLID原则)

  1. 开闭原则:一个软件实体,如类,模块和函数应该对扩展开发,对修改关闭.既软件实体应尽量在不修改原有代码的情况下进行扩展.
  2. 里氏替换原则:所有引用父类的方法必须能透明的使用其子类的对象
  3. 依赖倒置原则:高层模块不应该依赖底层模块,二者都应该依赖其抽象,抽象不应该依赖于细节,细节应该依赖抽象,换而言之,要针对接口编程而不是针对实现编程
  4. 接口隔离原则:使用多个专门的接口,而不是使用单一的总接口,即客户端不应该依赖那些并不需要的接口
  5. 迪米特法则:一个软件实体应该尽可能的少与其他实体相互作用
  6. 单一直责原则:不要存在多个导致类变更的原因.即一个类只负责一项职责

3、接口

  1. 定义:一种特殊的类,声明了若干方法,要求继承该接口的类必须实现这种方法
  2. 作用:限制继承接口的类的方法的名称及调用方式,隐藏了类的内部实现

设计模式分类

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

一、创建型模式

1、简单工厂模式

  1. 内容:不直接向客户端暴露对象创建的实现细节,而是通过一个工厂类来负责创建产品类的实例。
  2. 角色:
    • 工厂角色(Creator)
    • 抽象产品角色(Product)
    • 具体产品角色(Concrete Product)
  3. 优点:
    • 隐藏了对象创建的实现细节
    • 客户端不需要修改代码
  4. 缺点:
    • 违反了单一职责原则,将创建逻辑几种到一个工厂类里
    • 当添加新产品时,需要修改工厂类代码,违反了开闭原则
from abc import ABCMeta, abstractmethod

class Payment(metaclass=ABCMeta):
    # 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 PaymentFactory:
    #工厂角色
    def create_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 = PaymentFactory()
p = pf.create_payment('huabei')
p.pay(100)
factory.py

2、工厂方法模式

  1. 内容:定义一个用于创建对象的接口(工厂接口),让子类决定实例化哪一个产品类。
  2. 角色:
    • 抽象工厂角色(Creator)
    • 具体工厂角色(Concrete Creator)
    • 抽象产品角色(Product)
    • 具体产品角色(Concrete Product)
  3. 适用场景:
    • 需要生产多种,大量复杂对象的时候
    • 需要降低代码耦合度的时候
    • 当系统中的产品类经常需要扩展的时候
  4. 优点:
    • 每个具体产品都对应一个具体工厂类,不需要修改工厂类代码
    • 隐藏了对象创建的实现细节
  5. 缺点:
    • 每增加一个具体产品类,就必须增加一个相应的具体工厂类
from abc import ABCMeta, abstractmethod


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


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

    def pay(self, money):
        if self.use_huaei:
            print("花呗支付%d元." % money)
        else:
            print("支付宝余额支付%d元." % money)


class WechatPay(Payment):
    # 具体产品
    def pay(self, money):
        print("微信支付%d元." % money)



class PaymentFactory(metaclass=ABCMeta):
    # 抽象工厂
    @abstractmethod
    def create_payment(self):
        pass


class AlipayFactory(PaymentFactory):
    # 具体工厂
    def create_payment(self):
        return Alipay()


class WechatPayFactory(PaymentFactory):
    # 具体工厂
    def create_payment(self):
        return WechatPay()


class HuabeiFactory(PaymentFactory):
    # 具体工厂
    def create_payment(self):
        return Alipay(use_huabei=True)

# client

pf = HuabeiFactory()
p = pf.create_payment()
p.pay(100)

#如果要新增支付方式
class BankPay(Payment):
    # 具体产品
    def pay(self, money):
        print("银行卡支付%d元." % money)

class BankPayFactory(PaymentFactory):
    # 具体工厂
    def create_payment(self):
        return BankPay()

bf = BankPayFactory()
b = bf.create_payment()
b.pay(200)
factory_method.py

3、抽象工厂模式

  1. 内容:定义一个工厂类接口,让工厂子类来创建一系列相关或相互依赖的对象。
  2. 角色:
    • 抽象工厂角色(Creator)
    • 具体工厂角色(Concrete Creator)
    • 抽象产品角色(Product)
    • 具体产品角色(Concrete Product)
    • 客户端(Client)
  3. 适用场景:
    • 系统要独立于产品的创建和组合时
    • 强调一系列相关产品的对象设计以便进行联合调试时
    • 提供一个产品类库,想隐藏产品的具体实现时
  4. 优点:
    • 将客户端与类的具体实现相分离
    • 每个工厂创建了一个完整的产品系列,使得易于交换产品系列
    • 有利于产品的一致性(即产品之间的约束关系)
  5. 缺点:
    • 难以支持新种类的(抽象)产品
  6. 举例:生产一部手机,需要手机壳、CPU、操作系统三类对象进行组装,其中每类对象都有不同的种类。对每个具体工厂,分别生产一部手机所需要的三个对象。
  7. 对比:相比工厂方法模式,抽象工厂模式中的每个具体工厂都生产一套产品。
from abc import abstractmethod, ABCMeta


# ------抽象产品------

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("苹果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()


# ------客户端------


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()
abstract_factory.py

4、建造者模式

  1. 内容:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
  2. 角色:
    • 抽象建造者(Builder)
    • 具体建造者(Concrete Builder)
    • 指挥者(Director)
    • 产品(Product)
  3. 适用场景:
    • 当创建复杂对象的算法应该独立于对象的组成部分以及它的装配方式
    • 当构造过程允许被构造的对象有不同的表示
  4. 优点:
    • 隐藏了一个产品的内部结构和装配过程
    • 将构造代码与表示代码分开
    • 可以对构造过程进行更精细的控制
  5. 对比:建造者模式与抽象工厂模式相似,也用来创建复杂对象。主要区别是建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列的产品对象。
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 = Monster()
director = PlayerDirector()
p = director.build_player(builder)
print(p)
builder.py

5、单例模式

  1. 内容:保证一个类只有一个实例,并提供一个访问它的全局访问点。
  2. 角色:
    • 单例(Singleton)
  3. 适用场景:
    • 当一个类只能有一个实例而客户可以从一个众所周知的访问点访问它时
  4. 优点:
    • 对唯一实例的受控访问
    • 单例相当于全局变量,但防止了命名空间被污染

单例的多种实现方式

# mysingleton.py
class My_Singleton(object):
    def foo(self):
        pass
my_singleton = My_Singleton()

#将上面的代码保存在文件 mysingleton.py 中,然后这样使用:
from mysingleton import my_singleton
my_singleton.foo()
1.使用模块
#1.不能支持多线程的单例模式
class Singleton(object):
    @classmethod
    def instance(cls, *args, **kwargs):
        if not hasattr(Singleton, '_instance'):
            Singleton._instance = Singleton()
        return Singleton._instance

a = Singleton.instance()
b = Singleton.instance()
print(a == b)  # True

#2.加上多线程(过渡版-有问题)
import time
class Singleton(object):
    def __init__(self):
        time.sleep(1)
    @classmethod
    def instance(cls,*args,**kwargs):
        if not  hasattr(Singleton,'_instance'):
            Singleton._instance=Singleton()
        return Singleton._instance

import threading
def task():
    obj = Singleton.instance()
    print(obj)

for i in range(10):
    t=threading.Thread(target=task)
    t.start()
"""
<__main__.Singleton object at 0x0000000001313828>
<__main__.Singleton object at 0x0000000001313748>
<__main__.Singleton object at 0x0000000001313908>
...
"""

#3、解决上面存在的问题,实现支持多线程的单列模式:
import time
import threading
class Singleton(object):
    _instance_lock = threading.Lock()
    def __init__(self):
        time.sleep(1)
    @classmethod
    def instance(cls,*args,**kwargs):
        with cls._instance_lock:
            if not hasattr(Singleton,'_instance'):
                Singleton._instance=Singleton()
                return Singleton._instance
            return Singleton._instance

def task():
    obj = Singleton.instance()
    print(obj)

for i in range(10):
    t=threading.Thread(target=task)
    t.start()

"""
<__main__.Singleton object at 0x00000000010B8278>
<__main__.Singleton object at 0x00000000010B8278>
<__main__.Singleton object at 0x00000000010B8278>
...
"""
####问题:创建实例只能调用Singleton.instance()来调用,不能用Singleton()来实现
2.利用类实现
import threading
class Singleton():
    def __init__(self,name):
        self.name=name

    _instance_lock = threading.Lock()
    def __new__(cls, *args, **kwargs):
        with cls._instance_lock:
            if not hasattr(cls,'_instance'):
                cls._instance = super().__new__(cls)
        return cls._instance

def task(i):
    Singleton(i)
    print(id(Singleton(i)))

if __name__ == '__main__':
    for i in range(10):
        t = threading.Thread(target=task, args=(i,))
        t.start()
3.使用__new__
"""
对象是类创建,创建对象时候类的__init__方法自动执行,对象()执行类的 __call__ 方法
类是type创建,创建类时候type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法)

obj = Foo()
第1步: 执行type的 __init__ 方法【类是type的对象】
第2步: 执行type的 __call__ 方法
第3步:调用 Foo类(是type的对象)的 __new__方法,用于创建对象。
第4步:调用 Foo类(是type的对象)的 __init__方法,用于对对象初始化。

obj()  执行 Foo 的__call__方法

class SingletonType(type):
    def __init__(self,*args,**kwargs):
        print(1)
        super(SingletonType,self).__init__(*args,**kwargs)

    def __call__(cls, *args, **kwargs):
        print(2)
        obj = cls.__new__(cls,*args, **kwargs)
        cls.__init__(obj,*args, **kwargs) # Foo.__init__(obj)
        return obj

class Foo(metaclass=SingletonType):
    def __init__(self,name):
        print(4)
        self.name = name
    def __new__(cls, *args, **kwargs):
        print(3)
        return object.__new__(cls)
    def __call__(self, *args, **kwargs):
        print(5)
        print(self.name)
obj1 = Foo('name')  # 1 2 3 4
obj1() # 5 name  执行 Foo 的__call__方法

"""
import threading
class Singleton(type):
    _instance_lock=threading.Lock()
    def __call__(cls, *args, **kwargs):
        with  cls._instance_lock:
            if not hasattr(cls,'_instance'):
                cls._instance=super(Singleton, cls).__call__(*args, **kwargs)
        return cls._instance

class Foo(metaclass=Singleton):
    def __init__(self,name):
        self.name=name

obj1 = Foo('name')
obj2 = Foo('name')
print(obj1==obj2) #true
4.基于metaclass方式实现

创建型模式小结

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

二、结构型模式

1、适配器模式

  1. 内容:将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
  2. 角色:
    • 目标接口(Target)
    • 待适配的类(Adaptee)
    • 适配器(Adapter)
  3. 适用场景:
    • 想使用一个已经存在的类,而它的接口不符合你的要求
    • (对象适配器)想使用一些已经存在的子类,但不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。
  4. 两种实现方式:
    • 类适配器:使用多继承
    • 对象适配器:使用组合
from abc import ABCMeta, abstractmethod


class Payment(metaclass=ABCMeta):
    # 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 NewApplePay(Payment, ApplePay):
#     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)

#NewBankPay().pay(100)

p = PaymentAdapter(BankPay())
p.pay(100)


# 组合

# class A:
#     pass
#
# class B:
#     def __init__(self):
#         self.a = A()
adapter.py

2、桥模式

  1. 内容:将一个事物的两个维度分离,使其都可以独立地变化。
  2. 角色:
    • 抽象(Abstraction)
    • 细化抽象(RefinedAbstraction)
    • 实现者(Implementor)
    • 具体实现者(ConcreteImplementor)
  3. 适用场景:
    • 当事物有两个维度上的表现,两个维度都可能扩展时。
  4. 优点:
    • 抽象和实现相分离
    • 优秀的扩展能力
from abc import ABCMeta, abstractmethod
#------维度1------
class Shape(metaclass=ABCMeta):
    def __init__(self, color):
        self.color = color

    @abstractmethod
    def draw(self):
        pass

#------维度2------
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)



shape = Line(Blue())
shape.draw()

shape2 = Circle(Green())
shape2.draw()
bridge.py

3、组合模式

  1. 内容:将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
  2. 角色:
    • 抽象组件(Component)
    • 叶子组件(Leaf)
    • 复合组件(Composite)
    • 客户端(Client)
  3. 适用场景:
    • 表示对象的“部分-整体”层次结构(特别是结构是递归的)
    • 希望用户忽略组合对象与单个对象的不同,用户统一地使用组合结构中的所有对象
  4. 优点:
    • 定义了包含基本对象和组合对象的类层次结构
    • 简化客户端代码,即客户端可以一致地使用组合对象和单个对象
    • 更容易增加新类型的组件
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))


# 叶子组件
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("------复合图形------")


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()
composite.py

4、外观模式

  1. 内容:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
  2. 角色:
    • 外观(facade)
    • 子系统类(subsystem classes)
  3. 优点:
    • 减少系统相互依赖
    • 提高了灵活性
    • 提高了安全性
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: # Facade
    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()
facade.py

5、代理模式

  1. 内容:为其他对象提供一种代理以控制对这个对象的访问。
  2. 角色:
    • 抽象实体(Subject)
    • 代理(Proxy)
    • 实体(RealSubject)
  3. 应用场景:
    • 远程代理:为远程的对象提供代理
    • 虚代理:根据需要创建很大的对象
    • 保护代理:控制对原始对象的访问,用于对象有不同访问权限时
  4. 优点:
    • 远程代理:可以隐藏对象位于远程地址空间的事实
    • 虚代理:可以进行优化,例如根据要求创建对象
    • 保护代理:允许在访问一个对象时有一些附加的内务处理
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', encoding='utf-8')
        print("读取文件内容")
        self.content = f.read()
        f.close()

    def get_content(self):
        return self.content

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

#远程代理
class RemoteProxy(Subject):
    def __init__(self,filename):
        self.subj =RealSubject(filename)
    def get_content(self):
        return self.subj.get_content()


#虚代理
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("无写入权限")



#subj = RealSubject("test.txt")
#subj.get_content()

subj = ProtectedProxy("test.txt")
print(subj.get_content())
subj.set_content("abc")
proxy.py

三、行为型模式

1、责任链模式

  1. 内容:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
  2. 角色:
    • 抽象处理者(Handler)
    • 具体处理者(ConcreteHandler)
    • 客户端(Client)
  3. 适用场景:
    • 有多个对象可以处理一个请求,哪个对象处理由运行时决定
    • 在不明确接收者的情况下,向多个对象中的一个提交一个请求
  4. 优点:
    • 降低耦合度:一个对象无需知道是其他哪一个对象处理其请求
  5. 缺点:
    • 请求不保证被接收,链的末端没有处理或链配置错误
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("部门经理准假%s天" % day)
        else:
            print("部门经理职权不足")
            self.next.handle_leave(day)


class ProjectDirector(Handler):
    def __init__(self):
        self.next = DepartmentManager()

    def handle_leave(self, day):
        if day <= 3:
            print("项目主管准假%d天" % day)
        else:
            print("项目主管职权不足")
            self.next.handle_leave(day)

# Client


day = 12
h = ProjectDirector()
h.handle_leave(day)
chain_of_responsibility.py
from abc import ABCMeta, abstractmethod
#--模仿js事件处理
class Handler(metaclass=ABCMeta):
    @abstractmethod
    def add_event(self,func):
        pass

    @abstractmethod
    def handler(self):
        pass

class BodyHandler(Handler):
    def __init__(self):
        self.func = None

    def add_event(self,func):
        self.func = func

    def handler(self):
        if self.func:
            return self.func()
        else:
            print('已经是最后一级,无法处理')


class ElementHandler(Handler):

    def __init__(self,successor):
        self.func = None
        self.successor = successor

    def add_event(self,func):
        self.func = func

    def handler(self):
        if self.func:
            return self.func()
        else:
            return self.successor.handler()


#客户端
body = {'type': 'body', 'name': 'body', 'children': [], 'father': None}

div = {'type': 'div', 'name': 'div', 'children': [], 'father': body}

a = {'type': 'a', 'name': 'a', 'children': [], 'father': div}

body['children'] = div
div['children'] = a

body['event_handler'] = BodyHandler()
div['event_handler'] = ElementHandler(div['father']['event_handler'])
a['event_handler'] = ElementHandler(a['father']['event_handler'])

def attach_event(element,func):
    element['event_handler'].add_event(func)

#测试
def func_div():
    print("这是给div的函数")

def func_a():
    print("这是给a的函数")

def func_body():
    print("这是给body的函数")

attach_event(div,func_div)
#attach_event(a,func_a)
attach_event(body,func_body)

a['event_handler'].handler()
模仿js事件处理

2、观察者模式

  1. 内容:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时, 所有依赖于它的对象都得到通知并被自动更新。观察者模式又称“发布-订阅”模式
  2. 角色:
    • 抽象主题(Subject)
    • 具体主题(ConcreteSubject)——发布者
    • 抽象观察者(Observer)
    • 具体观察者(ConcreteObserver)——订阅者
  3. 适用场景:
    • 当一个抽象模型有两方面,其中一个方面依赖于另一个方面。将这两者封装在独立对象中以使它们可以各自独立地改变和复用。
    • 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少对象有待改变。
    • 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之,你不希望这些对象是紧密耦合的。
  4. 优点:
    • 目标和观察者之间的抽象耦合最小
    • 支持广播通信
  5. 缺点:
    • 多个观察者之间互不知道对方的存在,因此一个观察者对主题的修改可能造成错误的更新
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__()
        self.__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() # 推送


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 = "公司今年业绩非常好,给大家发奖金!!!"
print(s1.company_info)
print(s2.company_info)
notice.detach(s2)
notice.company_info = "公司明天放假!!!"
print(s1.company_info)
print(s2.company_info)
observer.py

3、策略模式

  1. 内容:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
  2. 角色:
    • 抽象策略(Strategy)
    • 具体策略(ConcreteStrategy)
    • 上下文(Context)
  3. 优点:
    • 定义了一系列可重用的算法和行为
    • 消除了一些条件语句
    • 可以提供相同行为的不同实现
  4. 缺点:
    • 客户必须了解不同的策略
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()
strategy.py

4、模板方法模式

  1. 内容:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
  2. 角色:
    • 抽象类(AbstractClass):定义抽象的原子操作(钩子操作);实现一个模板方法作为算法的骨架。
    • 具体类(ConcreteClass):实现原子操作
  3. 适用场景:
    • 一次性实现一个算法的不变的部分
    • 各个子类中的公共行为应该被提取出来并集中到一个公共父类中以避免代码重复
    • 控制子类扩展
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()

        
#子类中只需要实现部分算法,而不需要实现所有的逻辑
#-----具体类--------
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()
template_method.py
原文地址:https://www.cnblogs.com/bubu99/p/10534331.html