Python 设计模式

什么是设计模式?

设计模式是经过总结、优化的,对我们经常会碰到的一些编程问题的可重用解决方案。一个设计模式并不像一个类或一个库那样能够直接作用于我们的代码。反之,设计模式更为高级,它是一种必须在特定情形下实现的一种方法模板。设计模式不会绑定具体的编程语言。一个好的设计模式应该能够用大部分编程语言实现(如果做不到全部的话,具体取决于语言特性)。最为重要的是,设计模式也是一把双刃剑,如果设计模式被用在不恰当的情形下将会造成灾难,进而带来无穷的麻烦。然而如果设计模式在正确的时间被用在正确地地方,它将是你的救星。

起初,你会认为“模式”就是为了解决一类特定问题而特别想出来的明智之举。说的没错,看起来的确是通过很多人一起工作,从不同的角度看待问题进而形成的一个最通用、最灵活的解决方案。也许这些问题你曾经见过或是曾经解决过,但是你的解决方案很可能没有模式这么完备。

虽然被称为“设计模式”,但是它们同“设计“领域并非紧密联系。设计模式同传统意义上的分析、设计与实现不同,事实上设计模式将一个完整的理念根植于程序中,所以它可能出现在分析阶段或是更高层的设计阶段。很有趣的是因为设计模式的具体体现是程序代码,因此可能会让你认为它不会在具体实现阶段之前出现(事实上在进入具体实现阶段之前你都没有意识到正在使用具体的设计模式)。

可以通过程序设计的基本概念来理解模式:增加一个抽象层。抽象一个事物就是隔离任何具体细节,这么做的目的是为了将那些不变的核心部分从其他细节中分离出来。当你发现你程序中的某些部分经常因为某些原因改动,而你不想让这些改动的部分引发其他部分的改动,这时候你就需要思考那些不会变动的设计方法了。这么做不仅会使代码可维护性更高,而且会让代码更易于理解,从而降低开发成本。

这里列举了三种最基本的设计模式:

  1. 创建模式,提供实例化的方法,为适合的状况提供相应的对象创建方法。
  2. 结构化模式,通常用来处理实体之间的关系,使得这些实体能够更好地协同工作。
  3. 行为模式,用于在不同的实体建进行通信,为实体之间的通信提供更容易,更灵活的通信方法。

设计模式的六大原则

开闭原则:软件实体如类,模块,函数应该对扩展开放,对修改关闭 
里氏替换原则:所有饮用积累的地方必须透明地使用其子类的对象
依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程
接口隔离原则:使用多个专门的接口,而不应该使用单一的总接口,即客户端不应该依赖那么它不需要的接口
迪米特法则:软件实体应当尽可能少地与其他实体发生相互作用
单一职责原则:不要存在多于一个导致类变更的原因。通俗的说,一个类只负责一项职责

哪些设计模式?

创建型

1. Factory Method(工厂方法)

2. Abstract Factory(抽象工厂)

3. Builder(建造者)

4. Prototype(原型)

5. Singleton(单例)

结构型

6. Adapter Class/Object(适配器)

7. Bridge(桥接)

8. Composite(组合)

9. Decorator(装饰)

10. Facade(外观)

11. Flyweight(享元)

12. Proxy(代理)

行为型

13. Interpreter(解释器)

14. Template Method(模板方法)

15. Chain of Responsibility(责任链)

16. Command(命令)

17. Iterator(迭代器)

18. Mediator(中介者)

19. Memento(备忘录)

20. Observer(观察者)

21. State(状态)

22. Strategy(策略)

23. Visitor(访问者)

创建型模式

1、单例模式

看着碍眼,首先把之前提到过的最容易理解的讲掉。

内容:保证一个类只有一个实例,并提供一个访问它的全局访问点
优点:
    1、对唯一实例的受控访问
    2、单例相当于全局变量,但防止了命名空间被污染

代码实现:

class Singleton(object):
    def __new__(cls, *args, **kwargs):
        if not hasattr(cls, '_instance'):
            cls._instance = super(Singleton, cls).__init__(cls)
        return cls._instance


class MyClass(Singleton):
    def __init__(self, name=None):
        self.name = name

先补充一个概念

类接口

#python 类的第一种接口写法


class Payment:
    def pay(self, money):
        raise NotImplementedError  # 报错,没用重写此方法


class Alipay(Payment):
    def pay(self, money):
        print('支付宝支付%s元' % money)


class Wechatpay(Payment):
    def pay(self, money):
        print('微信支付%s元' % money)


class Testpay(Payment):
    def fuqian(self, money):
        print('money', money)


def payx(payment, money):
    payment.pay(money)
payx(Testpay(), 100)


# 第二种接口写法
from abc import ABCMeta, abstractmethod


class Payment(metaclass=ABCMeta):
    @abstractmethod  # 类的抽象方法
    def pay(self, money):
        pass


class Alipay(Payment):
    def pay(self, money):
        print('支付宝支付%s元' % money)


class Wechatpay(Payment):
    pass

def payx(payment, money):
    payment.pay(money)


payx(Wechatpay(), 100)

在Python中实现抽象方法最简单地方式是:上面的接口一的写法,任何继承自Payment的类必须覆盖实现方法pay,否则会抛出异常。这种抽象方法的实现有它的弊端,如果你写一个类继承Pizza,但是忘记实现get_radius,异常只有在你真正使用的时候才会抛出来。

还有一种方式可以让错误更早的触发,使用Python提供的abc模块,对象被初始化之后就可以抛出异常:上面的接口二的写法。使用@abstractmethod后,当你尝试初始化Pyament或者任何子类的时候立马就会得到一个TypeError,而无需等到真正调用pay的时候才发现异常。

简单工厂模式

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

  2、抽象产品角色 Payment

  3、具体产品角色 Alipay & WechatPay
优点:
  1、隐藏了对象创建的实现细节  # 实例化过程,还有余额宝创建过程
  2、客户端不需要修改代码  # 客户端只有调用,传入参数就好
缺点:
  1、违反了单一职责原则,将创建逻辑集中到一个工厂类里
  2、当添加新产品时,需要修改工厂代码,违反了开闭原则

#!/usr/bin/env python3
# encoding: utf-8
# Author: Dandy
from abc import abstractmethod, ABCMeta


class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass


class Alipay(Payment):

    def __init__(self, enabled_yuebao = False):
        self.enabled_yuebao = enabled_yuebao

    def pay(self, money):
        if self.enabled_yuebao:
            print('余额宝支付%s元' % money)
        else:
            print('支付宝支付%s元' % money)


class Wechatpay(Payment):
    def pay(self, money):
        print('微信支付%s元' % money)


class PaymentFactory:
    def create_payment(self, method):
        if method == 'alipay':
            return Alipay()
        elif method == 'yuebaopay':
            return Alipay(True)
        elif method == 'wechatpay':
            return Wechatpay()
        else:
            raise NameError(method)


f = PaymentFactory()
p = f.create_payment('yuebaopay')
p.pay(100)

# 不暴露出创建对象的实现细节,而直接将实例化对象返回

具体产品继承并重写抽象类,工厂实例化具体产品到对象。 

工厂方法模式(Factory Method)

 

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

角色:
  1、抽象工厂角色  payment factory
  2、具体工厂角色  allipay factory
  3、抽象产品角色  payment
  4、具体产品角色  alipay

工厂方法模式相比简单工厂模式将每个具体产品都对应了一个具体工厂。

使用场景

  1、需要生产多种,大量复杂对象的时候
  2、需要降低耦合度的时候
  3、当系统中的产品种类需要经常扩展的时候

优点:
  1、每个具体产品都对应一个具体工厂类,不需要修改工厂类代码
  2、隐藏了对象创建的实现细节
缺点:
  1、每增加一个具体产品类,就必须增加一个相应的具体工厂类 

from abc import abstractmethod, ABCMeta


class PaymentFactory(metaclass=ABCMeta):
    @abstractmethod
    def create_payment(self):
        pass


class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass


class AlipayFactory(PaymentFactory):

    def create_payment(self):
        return Alipay()


class ApplePayFactory(PaymentFactory):
    def create_payment(self, money):
        return ApplePay()


class Alipay(Payment):
    def pay(self, money):
        print('支付宝支付%s元' % money)


class ApplePay(Payment):
    def pay(self, money):
        print('苹果支付%s元' % money)


ali = AlipayFactory()
ali = ali.create_payment()
ali.pay(120)

抽象产品类被具体产品类继承,具体工厂继承抽象工厂并调用具体产品,不同的具体工厂返回不同的相对应的具体产品对象给用户。

抽象工厂模式(Abstract Factory)

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

代码

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


class Android(OS):
    def show_os(self):
        print('Android系统')


class IOS(OS):
    def show_os(self):
        print('IOS 系统')


# ***************抽象工厂**************
class PhoneFactory(metaclass=ABCMeta):
    @abstractmethod
    def make_shell(self):
        pass

    @abstractmethod
    def make_cpu(self):
        pass

    @abstractmethod
    def make_os(self):
        pass


# ***************** 具体工厂 *************

class AppleFactory(PhoneFactory):
    def make_cpu(self):
        return AppleCPU()

    def make_os(self):
        return IOS()

    def make_shell(self):
        return AppleShell()


class HuaweiFactory(PhoneFactory):
    def make_cpu(self):
        return SnapDragonCPU()

    def make_shell(self):
        return BigShell()

    def make_os(self):
        return Android()

# ************************ 客户端 **************************
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(AppleFactory())
p1.show_info()

建造者模式

内容:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
角色:
  1、抽象建造者
  2、具体建造者
  3、指挥者
  4、产品
建造者模式与抽象工厂模式相似,也用来创建复杂对象。主要区别在于见照着模式着重一步步构造一个复杂对象,二抽象工厂模式着重于多个系列的产品对象
适用场景:
  1、当创建复杂对象的算法(director),应该独立于该对象的组成部分以及他们的装配方法(builder)时
  2、当构造过程允许被构造的对象有不同的表示时(不同builder)
优点:
  1、隐藏了一个产品的内部结构和装配过程
  2、将构造代码与表示代码分开
  3、可以对构造过程进行更精细的控制

from abc import abstractmethod, ABCMeta

# ***************** 产品 ***********


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.arm, self.body, self.leg)

# *************************** 抽象建造者 *********************************


class PlayerBuilder(metaclass=ABCMeta):
    @abstractmethod
    def build_face(self):
        pass

    @abstractmethod
    def build_arm(self):
        pass

    @abstractmethod
    def build_body(self):
        pass

    @abstractmethod
    def build_leg(self):
        pass

    @abstractmethod
    def get_player(self):
        pass


# *************************** 具体建造者 *********************************

class BeautifulWomenBuilder(PlayerBuilder):
    def __init__(self):
        self.player = Player()

    def build_face(self):
        self.player.face = '漂亮脸蛋'

    def build_arm(self):
        self.player.arm = '细胳膊'

    def build_body(self):
        self.player.body = '完美身材'

    def build_leg(self):
        self.player.leg = '大长腿'

    def get_player(self):
        return self.player


# ****************** 指挥者 *********************

class PlayDirector:
    def build_player(self, builder):
        builder.build_face()
        builder.build_body()
        builder.build_leg()
        builder.build_arm()
        return builder.get_player()


director = PlayDirector()
builder = BeautifulWomenBuilder()
person = director.build_player(builder)

print(person)

创建型模式小结


适用abstra factory、 prototype或者builder的设计甚至比适用factory method的那些设计更灵活,但他们也更加复杂。通常,设计以适用Factory method开始,并且设计者发现需要更大的灵活性时,设计便会向其他创建模式演化。当你在设计标准之间进行权衡的时候,了解多个模式可以给你提供更多的选择余地。
1、依赖于继承的创建型模式:工厂方法模式
2、依赖于组合的创建型模式:抽象工厂模式,创建者模式


工厂方法模式:一类产品,每类产品有多种
抽象工厂模式:多类产品,每类产品有多种
建造者模式:多类产品,每类产品有一种,目的是把多种产品攒成大产品

结构型模式

适配器模式

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

 代码:

from abc import abstractmethod, ABCMeta


class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self, money):
        pass


class Alipay(Payment):
    def pay(self, money):
        print('支付宝支付%s元' % money)


class Applepay(Payment):
    def pay(self, money):
        print('苹果支付%s元' % money)


# ************************* 新人代码 ******************************


class WeiXinZhiFu:
    def fuqian(self, money):
        print('微信支付%s元' % money)


class WangYinZhiFu:
    def fuqian(self, money):
        print('网银支付%s元' % money)


# 类适配器写法, 用继承
class WechatPay(Payment, WeiXinZhiFu):
    def pay(self, money):
        self.fuqian(money)


# 对象适配器  组合
class PayAdapter(Payment):
    def __init__(self, payment):
        self.payment = payment

    def pay(self, money):
        if hasattr(self, "pay"):
            return self.payment.pay(money)
        else:
            return self.payment.fuqian(money)


# paym = WechatPay()
# paym.pay(1000)

paym = PayAdapter(WangYinZhiFu())
paym.pay(1000)

组合模式

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

代码:

from abc import abstractmethod, ABCMeta


class Graphic(metaclass=ABCMeta):

    @abstractmethod
    def draw(self):
        pass

    @abstractmethod
    def add(self):
        pass

    def getchildren(self):
        pass


class Point(Graphic):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def draw(self):
        print(self)

    def add(self, graphic):
        raise TypeError

    def getchildren(self):
        raise TypeError

    def __str__(self):
        return "点(%s, %s)" % (self.x, self.y)


class Line(Graphic):
    def __init__(self, p1, p2):
        self.p1 = p1
        self.p2 = p2

    def draw(self):
        print(self)

    def add(self, graphic):
        raise TypeError

    def __str__(self):
        return "线段[%s, %s]" % (self.p1, self.p2)


class Picture(Graphic):
    def __init__(self):
        self.children = []

    def add(self, graphic):
        self.children.append(graphic)

    def getchildren(self):
        return self.children

    def draw(self):
        print('-----复合图形-----')
        for g in self.children:
            g.draw()
        print('------END-----')


# p1 = Point(1, 2)
# p2 = Point(3, 4)
# l = Line(p1, p2)
# print(l)

pic1 = Picture()
pic1.add(Point(1, 4))
pic1.add(Line(Point(1, 2), Point(3, 2)))
pic1.add(Line(Point(7, 8), Point(9, 4)))

pic2 = Picture()
pic2.add(Point(-1, -1))
pic2.add(Line(Point(-1, -2), Point(3, 2)))

pic = Picture()
pic.add(pic1)
pic.add(pic2)

pic.draw()

装饰模式

意图: 
动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator 模式相比生成子类更为灵活。 
适用性:

 在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

 处理那些可以撤消的职责。

当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。

#!/usr/bin/python
#coding:utf8
'''
Decorator
'''
 
class foo(object):
    def f1(self):
        print("original f1")
 
    def f2(self):
        print("original f2")
 
 
class foo_decorator(object):
    def __init__(self, decoratee):
        self._decoratee = decoratee
 
    def f1(self):
        print("decorated f1")
        self._decoratee.f1()
 
    def __getattr__(self, name):
        return getattr(self._decoratee, name)
 
u = foo()
v = foo_decorator(u)
v.f1()
v.f2()

代理模式


内容:为其他对象提供一种代理以控制对这个对象的访问
角色:
  1、抽象实体
  2、实体
  3、代理
适用场景:
  1、远程代理:为远程的对象提供代理
  2、虚代理:根据需要创建很大的对象
  3、保护代理:控制对原始对象的访问,用于对象有不同访问权限时
优点:
  1、远程代理:可以隐藏对象位于远程地址空间的事实
  2、虚代理:可以进行优化,例如根据要求创建对象
  3、保护代理:允许在访问一个对象时有一些附加的内务处理

from abc import ABCMeta, abstractmethod


class Subject(metaclass=ABCMeta):
    @abstractmethod
    def get_content(self):
        pass


class RealSubject(Subject):
    def __init__(self, filename):
        print('读取%s文件内容' % filename)
        f = open(filename)
        self.content = f.read()
        f.close()

    def get_content(self):
        return self.content


class ProxyA(Subject):
    def __init__(self, filename):  # 实例化的时候进行创建
        self.subj = RealSubject(filename)  # 处理结果存在content里面

    def get_content(self):  # get_content只是获取最终结果
        return self.subj.get_content()


# ************************** 虚代理 ****************************

class ProxyB(Subject):
    def __init__(self, filename):  # 实例化的时候只是保存文件名
        self.filename = filename
        self.subj = None

    def get_content(self):  # 调用get_content的时候再执行处理
        if not self.subj:
            self.subj = RealSubject(self.filename)
        return self.subj.get_content()


# ************************* 保护代理 ****************************
class ProxyC(Subject):
    def __init__(self, filename):
        self.subj = RealSubject(filename)

    def get_content(self):
        return '????'


filename = 'abc.txt'
username = input('>>>>:')
if username != 'alex':
    p = ProxyC(filename)
else:
    p = ProxyA(filename)

p.get_content()

行为型模式

责任链模式


内容:是多个对象都有机会处理请求,从而避免请求的发送和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,知道有一个对象处理它为止。
角色:
  1、抽象处理者
  2、具体处理者
  3、客户端
例:
  1、请假部门批准:lead ==》 部门经理 ==〉 总经理
  2、javascript事件浮升机制

代码:

from abc import ABCMeta, abstractmethod


class Handler(metaclass=ABCMeta):
    @abstractmethod
    def handle_leave(self, day):
        pass


class GeneralManagerHandler(Handler):
    def handle_leave(self, day):
        if day < 10:
            print('总经理批准%d天假' % day)
        else:
            print('呵呵')


class DepartmentManagerHandler(Handler):
    def __init__(self):
        self.successor = GeneralManagerHandler()

    def handle_leave(self, day):
        if day < 7:
            print('部门经理批准%d天假' % day)
        else:
            print('部门经理无权准假')
            self.successor.handle_leave(day)


class ProjectDirectorHandler(Handler):
    def __init__(self):
        self.successor = DepartmentManagerHandler()

    def handle_leave(self, day):
        if day < 3:
            print('项目主管批准%d天假' % day)
        else:
            print('项目主管无权准假')
            self.successor.handle_leave(day)


day = 10
h = ProjectDirectorHandler()
h.handle_leave(day)

还有个高端点的实例:

# ******************* 高级点的例子--模仿js时间处理 ***************************
class Handler(metaclass=ABCMeta):
    @abstractmethod
    def add_event(self):
        pass

    @abstractmethod
    def handle(self):
        pass


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

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

    def handle(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 handle(self):
        if self.func:
            return self.func()
        else:
            return self.successor.handle()


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'].append(div)
div['children'].append(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)

div['event_handler'].handle()

观察者模式


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

代码:

'''
Observer
'''
 
 
class Subject(object):
    def __init__(self):
        self._observers = []
 
    def attach(self, observer):
        if not observer in self._observers:
            self._observers.append(observer)
 
    def detach(self, observer):
        try:
            self._observers.remove(observer)
        except ValueError:
            pass
 
    def notify(self, modifier=None):
        for observer in self._observers:
            if modifier != observer:
                observer.update(self)
 
# Example usage
class Data(Subject):
    def __init__(self, name=''):
        Subject.__init__(self)
        self.name = name
        self._data = 0
 
    @property
    def data(self):
        return self._data
 
    @data.setter
    def data(self, value):
        self._data = value
        self.notify()
 
class HexViewer:
    def update(self, subject):
        print('HexViewer: Subject %s has data 0x%x' %
              (subject.name, subject.data))
 
class DecimalViewer:
    def update(self, subject):
        print('DecimalViewer: Subject %s has data %d' %
              (subject.name, subject.data))
 
# Example usage...
def main():
    data1 = Data('Data 1')
    data2 = Data('Data 2')
    view1 = DecimalViewer()
    view2 = HexViewer()
    data1.attach(view1)
    data1.attach(view2)
    data2.attach(view2)
    data2.attach(view1)
 
    print("Setting Data 1 = 10")
    data1.data = 10
    print("Setting Data 2 = 15")
    data2.data = 15
    print("Setting Data 1 = 3")
    data1.data = 3
    print("Setting Data 2 = 5")
    data2.data = 5
    print("Detach HexViewer from data1 and data2.")
    data1.detach(view2)
    data2.detach(view2)
    print("Setting Data 1 = 10")
    data1.data = 10
    print("Setting Data 2 = 15")
    data2.data = 15
 
if __name__ == '__main__':
    main()

策略模式

内容:定义一系列的算法,把他们一个个封装起来,并且使它们可以相互替换。本模式使得算法可独立于使用它的客户而变化。
角色:
  1、抽象策略
  2、具体策略
  3、上下文
适用场景:
  1、许多相关的类仅仅是行为有异
  2、需要使用一个算法的不同变体
  3、算法使用了客户端无需知道的数据
  4、一个类中的多种行为以多个条件语句的形式存在,可以将这些行为封装在不同的策略中。
优点:
  1、定义了一系列可重用的算法和行为
  2、消除了一些条件语句
  3、可以提供相同行为的不同实现
缺点:
  1、客户必须了解不同的策略
  2、策略与上下文之间的通信开销
  3、增加了对象的数目

代码:

from abc import ABCMeta, abstractmethod
import random


class Sort(metaclass=ABCMeta):
    @abstractmethod
    def sort(self, data):
        pass


class QuickSort(Sort):
    def quick_sort(self, data, left, right):
        if left < right:
            mid = self.partition(data, left, right)
            self.quick_sort(data, left, mid - 1)
            self.quick_sort(data, mid + 1, right)

    def partition(data, left, right):
        tmp = data[left]
        while left < right:
            while left < right and data[right] >= tmp:
                right -= 1
            data[left] = data[right]
            while left < right and data[left] <= tmp:
                left += 1
            data[right] = data[left]
        data[left] = tmp
        return left

    def sort(self, data):
        print('快速排序')
        return self.quick_sort(data, 0, len(data) - 1)


class MergeSort(Sort):
    def merge(self, data, low, mid, high):
        i = low
        j = mid + 1
        ltmp = []
        while i <= mid and j <= high:
            if data[i] < data[j]:
                ltmp.append(data[i])
                i += 1
            else:
                ltmp.append(data[j])
                j += 1
        while i <= mid:
            ltmp.append(data[i])
            i += 1
        while j <= high:
            ltmp.append(data[j])
            j += 1
        # print(ltmp)
        data[low: high + 1] = ltmp

    def mergesort(self, data, low, high):
        if low < high:
            mid = (low + high) // 2
            self.mergesort(data, low, mid)
            self.mergesort(data, mid + 1, high)
            self.merge(data, low, mid, high)

    def sort(self, data):
        print('归并排序')
        return self.mergesort(data, 0, len(data) - 1)


class Context:
    def __init__(self, data, strategy=None):
        self.data = data
        self.strategy = strategy

    def set_strategy(self, strategy):
        self.strategy = strategy

    def do_strategy(self):
        if self.strategy:
            self.strategy.sort(self.data)
        else:
            raise TypeError


li = list(range(10000))
random.shuffle(li)
context = Context(li, MergeSort())
context.do_strategy()

random.shuffle(context.data)

context.set_strategy(QuickSort())
context.do_strategy()


模版方法模式


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

代码:

from abc import ABCMeta, abstractmethod


class IOHandler(metaclass=ABCMeta):
    @abstractmethod
    def open(self, name):
        pass

    @abstractmethod
    def deal(self, change):
        pass

    @abstractmethod
    def close(self):
        pass

    def process(self, name, change):
        self.open(name)
        self.deal(change)
        self.close()


class FileHandler(IOHandler):
    def open(self, name):
        self.file = open(name, 'w')

    def deal(self, change):
        self.file.write(change)

    def close(self):
        self.file.close()


f = FileHandler()

f.process('abc.txt', 'hello world')

大概就抽取一些重要的介绍,具体的可以上网找找blog看看

比如:https://www.cnblogs.com/Liqiongyu/p/5916710.html

或者大王的:https://www.cnblogs.com/alex3714/articles/5760582.html

原文地址:https://www.cnblogs.com/wuzdandz/p/9256200.html