设计模式

设计模式

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

面向对象的复习(按顺序说 是递进的关系)

  封装:把数据data 和函数也叫方法 封装到一个类里面 类内和类外 私有和公有

  继承:两个类之间想复用代码 不想重写一遍

  多态:python本身是多态语言 不用管它

 

接口:若干抽象方法的集合 (就是一种特殊的类)

  作用:限制实现结构的类必须按照接口给定的调用方式实现这些方法

     对高层模块隐藏了类的内部实现

# 第一种接口
# class Payment:
#     def pay(self, money):
#         raise NotImplementedError

from abc import ABCMeta, abstractmethod

# 第二种
# 接口(类似于一个规定 想要使用某个功能必须按照的规则来)
# class Payment(metaclass=ABCMeta):
#     @abstractmethod  # 抽象方法abstract class
#     def pay(self, money):
#         pass
#
#
# class Alipay(Payment): # 实现了Payment接口
#     def pay(self, money): # 保证和父类此抽象方法的参数和返回值一样  其他的无所谓可以改 也可以添加别的方法
#         print("支付宝支付%d元." % money)
#
#
# class WechatPay(Payment):# 实现了Payment接口
#     def pay(self, money): 
#         print("微信支付%d元." % money)
#
#
## 高层代码 调用了低层模块
# p = WechatPay()
# p.pay(100)

 

面向对象设计的SOLID原则

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

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

# 里氏替换原则
#
class User: # def show_name(self): # pass # # class VIPUser(User): # def show_name(self):# 保证和父类的方法 参数返回的东西要一致 # pass # # def show_user(u): # res = u.show_name() # 高层代码

依赖倒置原则:高层模块不应该依赖低层模块(底层有修改不能影响高层)

       二者都应该依赖其抽象(接口)(写程序应该先定义接口 表明了高层代码需要哪些函数  低层模块去实现接口)

       抽象(接口)不应该依赖细节(实现和调用接口的) ,细节应该依赖抽象(换言之 要针对接口编程 而不是针对实现编程) 

接口隔离原则:使用多个专门的接口,而不使用单一的总接口(即客户端(高层代码)不应该依赖那些它不需要的接口)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("青蛙走飞o")

单一职责原则:不要存在多于一个导致类变更的原因(一个类只负责一项职责)

 

设计模式分类

创建型模式(5种 负责生产对象):工厂方法、抽象工厂、创建者、原型、单例等模式

结构型模式(7种 负责类):适配器、桥、组合、装饰、外观、享元、代理等模式

行为型模式(11种 负责方法):解释器、责任链‘、命令、迭代器、中介者、备忘录、观察者、状态、策略、访问者、模板方法等模式

 

创建型模式--简单工厂模式

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

角色:

  工厂角色

  抽象角色 (接口)

  具体产品角色(具体实现接口)

优点:

  隐藏了对象创建的实现细节

  客户端不需要修改代码(高层代码)

缺点:

  违反了单一职责原则 将创建逻辑集中到一个工厂类里  (所以此模式没在23种设计模式中)

  当添加新产品时候 需要修改工厂类代码 违反了开闭原则

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: # 支付工厂 生产支付对象
    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)

 

工厂方法模式(用的比较多)

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

角色:

  抽象工厂角色

  具体工厂角色

  抽象产品角色

  具体产品角色

优点:

  每一个具体产品都对应一个具体类,不需要修改工厂类代码

  隐藏了对象创建的实现细节

缺点:

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

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/12/1

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 BankPay(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)


class BankPayFactory(PaymentFactory):
    def create_payment(self):
        return BankPay()


# client
pf = HuabeiFactory() # 创建具体工厂类对象
p = pf.create_payment() # 创建具体产品支付类对象
p.pay(100)

 

抽象工厂模式(用的少)

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

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

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

角色:

  抽象工厂角色

  具体工厂角色

  抽象产品角色

  具体产品角色

  客户端

优点:

  将客户端与类的具体实现相分离

  每个工厂创建了一个完整的产品系列,使得易于与交换产品系列

  有利于产品的一致性(即产品之间的约束关系)

缺点:

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

  

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/12/1

from abc import abstractmethod, ABCMeta


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

class PhoneShell(metaclass=ABCMeta):# 手机壳
    @abstractmethod
    def show_shell(self):
        pass


class CPU(metaclass=ABCMeta): # cpu
    @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()

 

建造者模式

内容:将一个复杂对象的构建与它表示分离。使得同样的构建(PlayerDirector)过程可以创建不同的表示

角色:

  抽象建造者(接口 规定 我要创建哪几个小的对象 脑袋身子胳膊腿)

  具体建造者(建造这种对象表示 girl boy)

  指挥者 (控制组装)

  产品

建造者模式与抽象工厂模式相似,也用来创建复杂对象。主要区别是建造者模式着重一步步构造一个复杂对象,而抽象工厂模式着重于多个系列的产品对象

优点:

  隐藏了一个产品的内部结构和装配过程

  将构造代码与百事代码分开 (PlayerDirector)

  可以对构造过程进行更精细的控制 (PlayerDirector)

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/12/1

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)

 

单例模式

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

角色:

   单例

优点:

  对唯一实例的受控访问

  单例相当于全部变量 但防止了命名空间被污染

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/12/1

from abc import abstractmethod, ABCMeta

class Singleton: # 基类
    def __new__(cls, *args, **kwargs): # 面向对象用的 用来分配空间 整个对象的初始化用的
        if not hasattr(cls, "_instance"): # hasattr反射 看cls是不是有_instance类属性 没有这个类属性说明这个类没有实例
            cls._instance = super(Singleton, cls).__new__(cls) # 那就创建一个这个实例
        return cls._instance


class MyClass(Singleton): # 继承new方法
    def __init__(self, a):
        self.a = a


a = MyClass(10) # 创建对象a 调用init方法前会调用new方法 发现myclass没有__instance类属性这个东西 
          # 那就调用父类object的new方法把maclass类传进去 返回myclass实例
          # 把__instance返回回来给赋值10
b
= MyClass(20)# 又来一个类对象 发现现在有__instance属性 刚才创建过了 又给a重新赋值了20 print(a.a) # 20 print(b.a) # 20 print(id(a), id(b)) # 同一个实例 id相同

创建型模型总结

抽象工厂模式和建造者模式相比于简单工厂模式和工厂方法模式而言更灵活也更复杂

通常情况下 设计以简单工厂模式或工厂方法开始,当你发现设计需要更大的灵活性的时候则像更复杂的设计模式演化

 

结构型模式--适配器模式

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

两种方式:

  类适配器:使用多继承

  对象适配器:使用组合

角色:

  目标接口

  待适配器的类

  适配器

使用场景:

  想使用一个已经存在的类 而它的接口不符合你的要求

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

#! /usr/bin/env python
# -*- coding: utf-8 -*-
# Date: 2018/12/1

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): # 继承Payment为了适配此接口 
#     def pay(self, money): # 继承Payment 为了让BankPay能实现此接口 和接口保持一致
#         self.cost(money) # 继承BankPay 复用之前的代码


# 适配器目的 第一和接口保持一直 第二要复用之前的代码
# 复用代码两种形式 第一继承 第二组合
# 对象适配器(通过组合复用代码)
class PaymentAdapter(Payment):
    def __init__(self, payment):
        self.payment = payment

    def pay(self, money): # 实现接口
        self.payment.cost(money) # 复用


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


# 组合(一个类里放入另外一个类的对象)

# class A:
#     pass
#
# class B: # B类复用A类代码
#     def __init__(self):
#         self.a = A() # B类的属性里加入A类对象

 

桥模式

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

角色:

  抽象

  细化抽象

  实现者

  具体实现者

应用场景:

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

优点:

  抽象和实现分离

  优秀的扩展能力

# coding: utf-8
# author: ztypl
# date:   2018/12/20

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)


####-------以上就是桥模式框架------#######

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

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

 

组合模式

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

角色:

  抽象组件

  叶子组件

  复合组件

  客户端

适用场景:

  表示对象的部分-整体层次结构(特别是结构是递归的)

  希望用户忽略组合对象与单个对象的不同,用户统一的使用组合结构中的所有对象

优点:

  定义了包含基本对象和组合对象的类层次结构

  简化客户端代码 即客户端可以一致地使用组合对象和单个对象

  更容易增加新类型地组件

# coding: utf-8
# author: ztypl
# date:   2018/12/21

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

 

外观模式:

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

角色:

  外观

  子系统

优点:

  减少系统相互依赖

  提高了灵活性

  提高了安全性

# coding: utf-8
# author: ztypl
# date:   2018/12/26


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

 

代理模式

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

应用场景:

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

  虚代理:根据需要创建很大地对象

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

角色:

  抽象实体

  实体

  代理

优点:

  远程代理:可以隐藏对象位于远程地址空间地事实

  虚代理:可以进行优化,例如根据要求创建对象

  保护代理:允许在访问一个对象时就有一些附加地内务处理

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

# subj = RealSubject('text.txt') # 创建对象直接就会加载文件了
# subj.get_content()

# 虚代理 文件会很大为了不占内存 先不加载文件
class VirtualProxy(Subject):
    def __init__(self,filename):
        self.filename = filename # 只是把filename存储一下
        self.subj = None # 不会真读取 只是存了一个文件名

    def get_content(self):
        if not self.subj: # 第一次是None 创建真实的对象读取文件
            self.subj = RealSubject(self.filename)
        return self.subj.get_content()
    def set_content(self,content):
        if not self.subj:  # 第一次是None 创建真实的对象写文件
            self.subj = RealSubject(self.filename)
        return self.subj.set_content(content)


# subj = VirtualProxy('text.txt') # 创建虚代理对象 不会真加载文件
# print(subj.get_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 = ProtectedProxy('text.txt')
print(subj.get_content()) # 读文件没问题
print(subj.set_content('sad')) # 抛一个错误

 

行为型模式-责任链模式

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

角色:

  抽象处理者

  具体处理者

  客户端

适用场景:

  有多个对象可以处理一个请求,那个对象处理由运行时决定

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

优点:

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

 

# coding: utf-8
# author: ztypl
# date:   2018/12/26

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)

 

观察者模式

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

角色:”

  抽象主题

  具体主题 --发布者

  抽象观察者

  具体观察者-- 订阅者

适用场景:

  当一个抽象模型又两方面 其中一个方面依赖于另一个方面,将这两者封装在独立对象中以使他们可以各自独立的改变和复用

  当一个对象的改变需要同时改变其他对象 而不知道具体又多少对象有待改变

  当一个对象必须通知其他对象 而它又不能假定其他对象是谁 换言之 你不希望这些对象是紧密耦合

优点:

  目标和观察者之间的抽象耦合最小

  支持广播通信

# coding: utf-8
# author: ztypl
# date:   2018/12/27

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) # self 是Notic类对象本身


class StaffNotice(Notice): # 具体发布者
    def __init__(self, company_info=None): # company_info公告属性
        super().__init__() # 声明observers属性
        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() # 推送 (赋值之后自动推送) 关键代码能够将发布者和订阅者company_info进行关联

obj = StaffNotice('abc') #
obj.company_info = 'xyz' #
print(obj.company_info) # xyz

class Staff(Observer): # 具体订阅者
    def __init__(self):
        self.company_info = None # 当发布者发布的话 自己的这个会自动更新

    def update(self, notice):
        self.company_info = notice.company_info # 将发布者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)

策略模式

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

角色:

  抽象策略

  具体策略

  上下文

优点:

  定义了一系列可重用的算法和行为

  消除了一些条件语句

  可以提供相同行为的不同实现

缺点:

  客户必须了解不同的策略

# coding: utf-8
# author: ztypl
# date:   2018/12/27

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

 

模板方法模式

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

角色:

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

  具体类:实现原子操作

适用场景:

  一次性实现一个算法的不变的部分

  各个子类中的公共行为应该被提取出来并集中到一个公共父类中以避免代码重复

  控制子类扩展

# coding: utf-8
# author: ztypl
# date:   2018/12/27

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() # 运行

 

posted @ 2022-05-28 11:12  贰号猿  阅读(32)  评论(0)    收藏  举报