Python之常用设计模式

一、设计模式与面向对象

1.1 设计模式概述

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

1.2 面向对象三大特性

封装

  • 类中封装了属性和方法(体现了类内和类外)
  • 私有化

继承

多态

1.3 接口

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

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

from abc import ABCMeta,abstractmethod

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

class WechatPay(Payment):
    def pay(self,money):
        pass
        print("微信支付了%d元"%money)

class AliPay(Payment):
    def pay(self,money):
        print("支付宝支付了%d元"%money)

w = WechatPay()
w.pay(100)

a = AliPay()
a.pay(200)

1.4 面向对象SOLID原则

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

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

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

  • 接口隔离原则:使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口。

    from abc import ABCMeta,abstractmethod
    
    class LandAnimal(metaclass=ABCMeta):
        @abstractmethod
        def walk(self):
            pass
    
    class AquatilicAnimal(metaclass=ABCMeta):
        @abstractmethod
        def swim(self):
            pass
    
    class BirdsAnimal(metaclass=ABCMeta):
        @abstractmethod
        def fly(self):
            pass
    
    class Tiger(LandAnimal):
        def walk(self):
            print("tiger is runing!!!")
    
    class Frog(AquatiliCAnimal):
        def swim(self):
            print("frog is swimming!!!")
    
    class Swallow(BirdsAnimal):
        def fly(self):
            print("swallows are flying in the blue sky!!!")
    
    t = Tiger()
    t.walk()
    f = Frog()
    f.swim()
    s = Swallow()
    s.fly()
    
  • 单一职责原则:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。

1.5 设计模式分类

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

二、简单工厂模式

在这里插入图片描述

  • 内容:不直接向客户端暴露对象创建的实现细节,而是通过一个工厂类来负责创建产品类的实例。
  • 角色:
    • 工厂角色(Creator)
    • 抽象产品角色(Product)
    • 具体产品角色(Concrete Product)
from abc import ABCMeta,abstractmethod

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

class WechatPay(Payment):
    def pay(self,money):
        pass
        print("微信支付了%d元"%money)

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 PaymentFatory:
    def create_payment(self,method):
        if method == 'alipay':
            return AliPay()
        elif method == 'huabei':
            return AliPay(use_huabei=True)
        elif method == "wechat":
            return WechatPay()
        else:
            raise TypeError("No such payment named %s"%method)

# client
pf = PaymentFatory()
p = pf.create_payment('alipay')
p.pay(1000)
  • 优点:

    • 隐藏了对象创建的实现细节
    • 客户端不需要修改代码
  • 缺点:

    • 违反了单一职责原则,将创建逻辑集中到一个工厂类里
    • 当添加新产品时,需要修改工厂类代码,违反了开闭原则

三、工厂方法模式

在这里插入图片描述

  • 内容:定义一个用于创建对象的接口(工厂接口),让子类决定实例化哪一个产品类。
  • 角色:
    • 抽象工厂角色(Creator)
    • 具体工厂角色(Concrete Creator)
    • 抽象产品角色(Product)
    • 具体产品角色 (Concrete Product)
# 抽象工厂
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_hb=True)


class BankPayFactory(PaymentFactory):
    """银联支付工厂"""
    def create_payment(self):
        return BankPay()


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


# 具体产品
class WechatPay(Payment):
    def pay(self, money):
        print(f"微信支付了{money}元")


class BankPay(Payment):
    def pay(self, money):
        print(f"银行卡支付了{money}元")


class AliPay(Payment):
    def __init__(self, use_hb=False):
        self.use_hb = use_hb

    def pay(self, money):
        if self.use_hb:
            print(f"花呗支付了{money}元")
        else:
            print(f"余额宝支付了{money}元")

# client
pf = HuaBeiFactory()
p = pf.create_payment()
p.pay(1000)

pf1 = BankPayFatory()
p1 = pf1.create_payment()
p1.pay(2000)
  • 优点:
    • 每个具体产品都对应一个具体工厂类,不需要修改工厂类代码
    • 隐藏了对象创建的具体实现细节
  • 缺点:
    • 每增加一个具体产品类,就必须增加一个相应的具体工厂类

四、抽象工厂模式

  • 内容:定义一个工厂类接口,让工厂子类来创建一系列相关或相互依赖的对象。
  • 例:生产一部手机,需要手机壳、CPU、操作系统三类对象进行组装,其中每类对象都有不同的种类。对每个具体工厂,分别生产一部手机需要的三个对象。
  • 相比工厂方法模式,抽象工厂模式中的每个具体工厂都生产一套产品。
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 MediaCPU(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 SnapDragonCPU()

    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)

print("====================小米手机====================")
p1 = make_phone(MiFactory())
p1.show_info()

print("====================华为手机====================")
p2 = make_phone(HuaweiFactory())
p2.show_info()

print("====================苹果手机====================")
p3 = make_phone(IphoneFactory())
p3.show_info()
  • 角色:

    • 抽象工厂角色(Creator)
    • 具体工厂角色(Concrete Creator)
    • 抽象产品角色(Product)
    • 具体产品角色(Concrete Product)
    • 客户端(Client)
  • 优点:

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

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

五、建造者模式

  • 内容:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
  • 角色:
    • 抽象建造者(Builder)
    • 具体建造者(Concrete Builder)
    • 指挥者(Director)
    • 产品(Product)
from abc import ABCMeta,abstractmethod

# 产品
class Player:
    def __init__(self,body=None,arm=None,leg=None,face=None):
        self.body = body
        self.arm = arm
        self.leg = leg
        self.face = face

    def __str__(self):
        return "{0},{1},{2},{3}".format(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_leg(self):
        pass

    @abstractmethod
    def build_arm(self):
        pass

# 具体建造者
class SexGirlBuilder(PlayerBuilder):
    def __init__(self):
        self.player = Player()
    
    def build_face(self):
        self.player.face = "漂亮脸蛋"

    def build_body(self):
        self.player.body = "苗条身材"

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

    def build_arm(self):
        self.player.arm = "修长胳膊"

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_leg(self):
        self.player.leg = "满腿毛"

    def build_arm(self):
        self.player.arm = "巨猿臂"

# 指挥者(控制组装顺序)
class PlayerDirector:
    def build_player(self,builder):
        builder.build_body()
        builder.build_face()
        builder.build_arm()
        builder.build_leg()
        return builder.player

# client
builder = SexGirlBuilder()
director = PlayerDirector()
p = director.build_player(builder)
print(p)
  • 建造者模式与抽象工厂模式相似,也用来创建复杂对象。主要区别时建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列的产品对象。
  • 优点:
    • 影藏了一个产品的内部结构和装配过程
    • 将构造代码与表示代码分开
    • 可以对构造过程进行更精细的控制

六、单例模式

  • 内容:保证一个类只有一个实例,并提供一个访问它的全局访问点。
  • 角色:
    • 单例(Singleton)
  • 优点:
    • 对唯一实例的受控访问
    • 单例相当于全局变量,但防止了命名空间被污染
# 单例模式
class Singleton:
    def __new__(cls,*args,**kwargs):
        if not hasattr(cls,"_instance"):
            cls._instance = super().__new__(cls)
        return cls._instance

class Myclass(Singleton):
    def __init__(self,num):
        self.num = num

a = Myclass(10)

b = Myclass(20)

print(a.num)
print(b.num)

print(id(a))

print(id(b))
# 单例模式
class Mysingleton:
    __obj = None
    __init_flag = True

    def __new__(cls,*args,**kwargs):
        if cls.__obj == None:
            cls.__obj = super().__new__(cls)

        return cls.__obj

    def __init__(self,name):
        if Mysingleton.__init_flag:
            print("init....")
            self.name = name
            Mysingleton.__init_flag = False

a = Mysingleton('aa')
print(a)
b = Mysingleton('bb')
print(b)
print(id(a))
print(id(b))
# 混合模式(单例+工厂)
class CarFactory:
    """工厂只需要一个"""
    __obj = None
    __init_flag = True

    def __new__(cls,*args,**kwargs):
        if cls.__obj == None:
            cls.__obj = super().__new__(cls)

        return cls.__obj

    def __init__(self):
        if CarFactory.__init_flag:
            print('init....')
            CarFactory.__init_flag = False
        

    def createCar(self,brand):
        if brand == "奔驰":
            return Benz()
        elif brand == "宝马":
            return BMW()
        elif brand == "比亚迪":
            return BYD()
        else:
            return "未知品牌,不能创建"


class Benz:
    pass

class BMW:
    pass

class BYD:
    pass


f  = CarFactory()
c1 = f.createCar("奔驰")
c2 = f.createCar("宝马")
print(c1)
print(c2)

f1 = CarFactory()
print('f:',f,id(f))
print('f1:',f1,id(f1))

七、适配器模式

  • 内容:将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
  • 两种实现方式:
    • 类适配器:使用多继承
    • 对象适配器:使用组合
from abc import ABCMeta,abstractmethod

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

class WechatPay(Payment):
    def pay(self,money):
        pass
        print("微信支付了%d元"%money)

class AliPay(Payment):
    def pay(self,money):
        print("支付宝支付了%d元"%money)

class BankPay:
    def cost(self,money):
        print("银联支付%d元"%money)

class ApplekPay:
    def cost(self,money):
        print("苹果支付%d元"%money)

# 类适配器
# class NewBankPay(Payment, BankPay):
#     def pay(self,money):
#         self.cost(money)

# p = NewBankPay()
# p.pay(2000)

# 对象适配器
# 实现接口统一(继承Payment),代码复用(组合(利用类的属性))
class PaymentAdapter(Payment):
    def __init__(self,payment):
        self.payment = payment

    def pay(self,money):
        self.payment.cost(money)

p = PaymentAdapter(ApplekPay())
p.pay(2500)

# 组合(在一个类中放入另一个类的对象,代码复用)
# class A:
#     pass

# class B:
#     def __init__(self):
#         self.a = A()
  • 角色:

    • 目标接口(Target)
    • 戴适配的类(Adaptee)
    • 适配器(Adapter)
  • 适用场景

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

八、桥模式

  • 内容:将一个事物的两个维度分离,使其都可以独立地变化。

  • 角色:

    • 抽象(Abstraction)
    • 细化抽象(Refined Abstraction)
    • 实现者(Implementor)
    • 具体实现者(Concrete Implementor)
  • 应用场景:

    • 当事物有两个维度上的表现,两个维导都可能扩展时
  • 优点:

    • 抽象和实现相分离
    • 优秀的扩展功能
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
shape = Rectangle(Red())
shape.draw()

shape1 = Circle(Green())
shape1.draw()

shape2 = Line(Blue())
shape2.draw()

九、组合模式

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

  • 角色:

    • 抽象组件(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))

# 叶子组件
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(1,3)
l1 = Line(Point(2,2),Point(6,8))
l2 = Line(Point(5,2),Point(8,9))
pic1 = Picture([p1,l1,l2])
# pic1.draw()

p2 = Point(4,3)
l2 = Line(Point(4,2),Point(5,6))
l3 = Line(Point(1,6),Point(2,8))
pic2 = Picture([p2,l2,l3])
# pic2.draw()

pic = Picture([pic1,pic2])
pic.draw()

十、外观模式

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

十一、代理模式

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

  • 应用场景:

    • 远程代理:为远程对象提供代理
    • 虚代理:根据需要创建很大的对象
    • 保护代理:控制对原始对象的访问,用于对象有不同访问权限时
  • 角色

    • 抽象实体(Subject)
    • 实体(Real Subject)
    • 代理(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
        print("读取文件内容....")
        f = open(filename,'r')
        self.content = f.read()
        print(self.content)
        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 VirtualSubject(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 self.subj:
            self.subj = RealSubject(self.filename)
        return self.subj.set_content(content)

class ProjectProxy(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 = VirtualSubject("test.txt")
# subj.get_content()
# subj.set_content("hello word!!!")

subj1 = ProjectProxy("test.txt")
# subj1.get_content()
subj1.set_content("哈哈,写不进去吧!!!")

十二、责任链模式

  • 内容:使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
  • 角色:
    • 抽象处理者(Handler)
    • 具体处理者(Concrete Handler)
    • 客户端(Client)
  • 使用场景
    • 有多个对象可以处理一个请求,哪个对象处理由运行时决定
    • 在不明确接受者的情况下,向多个对象中的一个提交一个请求
  • 优点
    • 降低耦合度:一个对象无需知道是其他哪一个对象处理其请求
from abc import ABCMeta,abstractmethod

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

# 具体处理者
class GeneralManager(Handle):
    def handle_leave(self,day):
        if day < 15:
            print("总经理准假%d天"%day)
        else:
            print("直接递交辞职报告吧!!!")

class DepartmentManager(Handle):
    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(Handle):
    def __init__(self):
        self.next = DepartmentManager()

    def handle_leave(self,day):
        if day <= 3:
            print("项目经理准假%d天"%day)
        else:
            print("超出职权范围内,请假申请转交部门经理处理")
            self.next.handle_leave(day)

# 客户端
# d = 18
# d = 2
d = 5
h = ProjectDirector()
h.handle_leave(d)

十三、观察者模式

  • 内容:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知

并被自动更新。观察者模式又称“发布-订阅”模式。

  • 角色:

    • 抽象主题(Subject)
    • 具体主题(Concre Subject)——发布者
    • 抽象观察者(Observer)
    • 具体观察者(Concrete Observer)——订阅者
  • 使用场景:

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

    • 目标和观察者之间的抽象耦合最小
    • 支持广播通信
from abc import ABCMeta,abstractmethod

class Observer(metaclass=ABCMeta):
    """
        抽象订阅者
        notice:是一个Notice的类
    """
    @abstractmethod
    def update(self,notice):
        pass

# 抽象发布者
class Notice:
    def __init__(self):
        self.observers = []

    def attach(self,obs):
        self.observers.append(obs)

    def delete_attach(self,obs):
        self.observers.remove(obs)

    def notify(self):
        for obs in self.observers:
            obs.update(self)

class StaffNotice(Notice):
    """具体发布者"""
    def __init__(self,commpany_info):
        super().__init__()
        self.__commpany_info = commpany_info

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

    @company_info.setter
    def company_info(self,info):
        self.__commpany_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.delete_attach(s2)
notice.company_info = "公司从明天起放假3天!!!"
print(s1.company_info)
print(s2.company_info)

十四、策略模式

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

  • 角色:

    • 抽象角色(Strategy)
    • 具体决策(Concrete Strategy)
    • 上下文(Context)
  • 优点:

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

    • 客户必须了解不同的策略
from abc import ABCMeta,abstractmethod

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

# 具体策略
class FastStrategy(Strategy):
    def excute(self,data):
        print("用较快的策略处理数据%s"%data)

class SlowStrategy(Strategy):
    def excute(self,data):
        print("用较慢的策略处理数据%s"%data)

# 上下文(封装数据和策略)
class Context:
    def __init__(self,strategy,data):
        self.strategy = strategy
        self.data = data

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

    def do_strategy(self):
        self.strategy.excute(self.data)

# Client
data = [1,3,9,100,85,66,77,33,22]
s = SlowStrategy()
s2 = FastStrategy()
c = Context(s,data)
c.do_strategy()

c.set_strategy(s2)
c.do_strategy()

十五、模板方法模式

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

  • 角色:

    • 抽象类(AbstractClass):定义抽象的原子操作(钩子操作);实现一个模板方法作为算法的骨架。
    • 具体类(Concrete Class):实现原子操作。
  • 使用场景:

    • 一次性实现算法的不变的部分
    • 各个子类中的公共行为应该被提取出来并集中到一个公共父类中以避免代码重复
    • 控制子类扩展
from abc import ABCMeta,abstractmethod
from time import sleep

class Windows(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 MyWindos(Windows):
    def __init__(self,msg):
        self.msg = msg

    def start(self):
       
        print("窗口开启")

    def stop(self):
        print("窗口关闭")

    def repaint(self):

        print(self.msg)

# client
MyWindos("hello...").run()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值