2023年10月4日星期三

py与设计模式

py与设计模式

reference
https://www.runoob.com/design-pattern

oop

封装、继承、多态
接口:若干抽象方法的集合

# python多态
## 1.抽象函数直接调用时raise未实现错误
class Payment:
    def pay(self,money):
        raise NotImplementedError

class Paypal(Payment):
    pass

a = Paypal()
a.pay(10)

---------------------------------------------------------------------------

NotImplementedError                       Traceback (most recent call last)

d:\Code\py\test\design\1.ipynb 单元格 2 line 1
      <a href='vscode-notebook-cell:/d%3A/Code/py/test/design/1.ipynb#W0sZmlsZQ%3D%3D?line=7'>8</a>     pass
     <a href='vscode-notebook-cell:/d%3A/Code/py/test/design/1.ipynb#W0sZmlsZQ%3D%3D?line=9'>10</a> a = Paypal()
---> <a href='vscode-notebook-cell:/d%3A/Code/py/test/design/1.ipynb#W0sZmlsZQ%3D%3D?line=10'>11</a> a.pay(10)


d:\Code\py\test\design\1.ipynb 单元格 2 line 5
      <a href='vscode-notebook-cell:/d%3A/Code/py/test/design/1.ipynb#W0sZmlsZQ%3D%3D?line=3'>4</a> def pay(self,money):
----> <a href='vscode-notebook-cell:/d%3A/Code/py/test/design/1.ipynb#W0sZmlsZQ%3D%3D?line=4'>5</a>     raise NotImplementedError


NotImplementedError: 
class Alipay(Payment):
    pass

a = Alipay()
a.pay(10)
success pay
## 2. 导包AbstractClass并使用装饰器@abstractmethod修饰抽象函数
from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self,money):
        pass

class Paypal(Payment):
    pass

a = Paypal()
a.pay(10)
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

d:\Code\py\test\design\1.ipynb 单元格 4 line 1
      <a href='vscode-notebook-cell:/d%3A/Code/py/test/design/1.ipynb#W4sZmlsZQ%3D%3D?line=7'>8</a> class Paypal(Payment):
      <a href='vscode-notebook-cell:/d%3A/Code/py/test/design/1.ipynb#W4sZmlsZQ%3D%3D?line=8'>9</a>     pass
---> <a href='vscode-notebook-cell:/d%3A/Code/py/test/design/1.ipynb#W4sZmlsZQ%3D%3D?line=10'>11</a> a = Paypal()
     <a href='vscode-notebook-cell:/d%3A/Code/py/test/design/1.ipynb#W4sZmlsZQ%3D%3D?line=11'>12</a> a.pay(10)


TypeError: Can't instantiate abstract class Paypal with abstract method pay

一般使用第二种,在创建时如果没有override就会报错,这里的payment就是接口
Alipay实现了Payment接口。
在这里中,之后的开发过程中不需要知道继承的内部实现,只需要看接口,对高层接口隐藏。

SOLID原则

开放封闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。
里氏替换原则:所有引用父类的地方必须能透明地使用其子类的对象

父类函数的参数和返回值与子类相同

依赖倒置原则: 高层模块不应该依赖低层模块,二者都应该依赖其抽象抽象不应该依赖细节;细节应该依赖抽象。换言之,要针对接口编程而不是针对实现编程
接口隔离原则: 使用多个专门的接口,而不使用单一的总接口,即客户端不应该依赖那些它不需要的接口
单一职责原则: 不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。

常用设计模式

设计模式分类

创建型模式:如何创建一个对象,隐藏底层模块逻辑,如几个工厂模式
结构型模式:多个类如何协同在一起工作
行为型模式:如何行为

创建型模式

简单工厂模式

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

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

class Alipay(Payment):
    def pay(self,money):
        print("success")

class payfactory:
    # 生产支付对象
    def create_payment(self,method):    # 如果类init有其他参数比如时间戳之类可以不需要用户传参,而是通过工厂,隐藏对象创建细节。
        if method == "Alipay":
            return Alipay()
        pass
         
pf = payfactory()
p = pf.create_payment("Alipay")
p.pay(123)
success

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

工厂方法模式

定义一个用于创建对象的接口 (工厂接口),让子类决定实例化哪一个产品类
抽象工厂、产品,具体工厂、产品
具体的工厂作为子类继承抽象工厂来重载创建对象的函数
每个具体产品都对应一个具体工厂类,不需要修改工厂类代码
每增加一个具体产品类,就必须增加一个相应的具体工厂类

抽象工厂模式

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

相比工厂方法模式,抽象工厂模式中的每个具体工厂都生产一系列的产品。
不方便加入新种类的抽象产品

from abc import ABCMeta, abstractmethod
# 抽象产品
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_epu(self):
        pass
    @abstractmethod
    def make_os(self):
        pass
# 具体产品
class cpu1(cpu):
    def show_cpu(self):
        print(1)

class os2(os):
    def show_os(self):
        print(2)

# 具体工厂
class pf223(PhoneFactory):
    def make_os(self):
        return os2()
    def make_epu(self):
        return cpu1()

# client
class Phone:
    def __init__(self,cpu:cpu,os:os) -> None:
        self.cpu = cpu
        self.os = os
        pass
    def show_info(self):
        self.cpu.show_cpu()
        self.os.show_os()

def make_phone(factory:PhoneFactory):
    return Phone(factory.make_epu(),factory.make_os())

p1=make_phone(pf223())
p1.show_info()
1
2

建造者模式

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
抽象建造者
具体建造者
指挥者,控制build的顺序。
产品

abstract builder->concrete builder->director

单例模式

一个类只有一个实例,并提供一个全局访问点

结构型模式

几个类如何组织在一起使用

适配器模式

内容:将一个类的接口转换成客户希望的另一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
目标接口,待适配对象,适配器
两种实现方式

  1. 类适配器: 使用多继承
  2. 对象适配器: 使用组合
from abc import ABCMeta,abstractmethod
# abstract Class
class Payment(metaclass=ABCMeta):
    @abstractmethod
    def pay(self,money):
        pass
class bakaPay:
    def cost(self,m):
        print(f"baka origin pay {m}")

#多继承
class newbaka(Payment,bakaPay):
    def pay(self, money):
        self.cost(m=money)

p = newbaka()
p.pay(123)

#如果好几个类都要适配->对象适配器
class paymentadapter(Payment):
    def __init__(self,payment) -> None:
        self.payment = payment
    
    def pay(self, money):
        self.payment.cost(money)

p= paymentadapter(bakaPay())# 传入对象
p.pay(456)
baka origin pay 123
baka origin pay 456

桥模式

将一个事务的两个维度分离,使其可以独立变化
如画图,一是形状二是颜色,并且二者缺一不可
可以在维度上任意拓展
抽象,细化抽象,实现者,具体实现者

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 rect(shape):
    name="rectangle"
    def draw(self):
        self.color.paint(self)

class black(Color):
    def paint(self, shape):
        print(f"black's {shape.name}")

t1 = rect(black())
t1.draw()
black's rectangle

组合模式

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

  • 抽象组件 (Component)
    • 叶子组件 (Leaf)
    • 复合组件(Composite)
  • 客户端 (Client)

简单对象->复杂对象->复杂对象
都有统一接口?组合模式!

表示对象的 部分-整体 结构,特别适用于结构是递归的
希望用户忽略组合对象与单个对象的不同,用户统一地使用组合结构中的所有对象

外观模式

内容:为子系统中的一组接口提供一个一致的界面,外观模式定义了1个高层接日,这个接口使得这一了系统更加容易使用
外观、子系统类
减耦、灵活、安全性

class CPU:
    def run(self):
        pass
    def stop(self):
        pass

class computer:# 外观模式的外观
    def __init__(self) -> None:
        self.c = CPU()
        # self.v = screen()
    
    def start(self):
        self.c.run()
        # self.v.run()
    
    def stop(self):
        self.c.stop()
        #self.v.stop()

代理模式

内容:为其他对象提供一种代理以控制对这个对象的访问
应用场景

  • 远程代理:为远程的对象提供代理
  • 虚代理: 根据需要创建很大的对象。
    • 如浏览器省流模式,不看图除非点击
  • 保护代理: 控制对原始对象的访问,用于对象有不同访问权限时
    • 普通用户和管理员

抽象实体,具体实体,代理

from abc import ABCMeta,abstractmethod
class Subject(metaclass=ABCMeta):
    @abstractmethod
    def get(self):
        pass
    @abstractmethod
    def set(self,content):
        pass


# 真实的东西和代理用起来一样。
class RealSubject(Subject):
    """
    真实对象
    """
    def __init__(self,filename) -> None:
        self.filename = filename
        with open(self.filename,"r",encoding="utf-8") as f:
            self.content = f.read()
        
    def get(self):
        return self.content
    
    def set(self,content):
        with open(self.filename,"r",encoding="utf-8") as w:
            w.write(content)

# 如果不用虚代理
# subj = RealSubject("mini.txt")  # 直接读取,并赋值给subj.content中

# 通过调用已有类
# 只有当要用get时才真read
class VProxy(Subject):
    def __init__(self,filename) -> None:
        self.filename = filename
        self.subj = None    # 不直接设置为real
    
    def get(self):
        if not self.subj:
            self.subj = RealSubject(filename=self.filename)
        return self.subj.get()
    
    # set 虚代理一般无set需求
    def set(self, content):
        if not self.subj:
            self.subj = RealSubject(filename=self.filename)
        return self.subj.set(content)

subjV = VProxy("mini.txt")
print(subjV.get())

class ProtectedProxy(Subject):
    def __init__(self,fi) -> None:
        self.subj = RealSubject(fi)
    def get(self):
        return self.subj.get()
    def set(self,c):
        raise PermissionError
    
subjp = ProtectedProxy("mini.txt")
print(subjp.get())
subjp.set("123")
幻想乡是东方Project系列故事的主要舞台,很多时候被用来指代整个东方Project世界。
幻想乡在过去是被称为「东之国远离人类村落的边境之地」的场所,深藏于日本境内的某片群山之中。
虽说如此,普通的手段是无法往来于幻想乡内外的,因为这里被常识的结界「博丽大结界」所隔断。
要说幻想乡有什么特别之处,那自然是——在现实中被视为「非常识」、「不存在」的妖怪、神明、魔法等等幻想,在这里都是理所当然的东西。
被否定、被遗忘、成为幻想之物的归宿,那就是幻想乡。
在这里,人类仍然敬畏神明,仍然谈论着魍魉魑魅。
巫女能在空中飞行也好、吸血鬼释放出血红雾气也好、冬天和夜晚不会结束也好、某位圣人突然复活也好……
妖怪等非人之物掀起异变、人类中的英雄前去应对,这便是幻想乡的日常。
幻想乡是东方Project系列故事的主要舞台,很多时候被用来指代整个东方Project世界。
幻想乡在过去是被称为「东之国远离人类村落的边境之地」的场所,深藏于日本境内的某片群山之中。
虽说如此,普通的手段是无法往来于幻想乡内外的,因为这里被常识的结界「博丽大结界」所隔断。
要说幻想乡有什么特别之处,那自然是——在现实中被视为「非常识」、「不存在」的妖怪、神明、魔法等等幻想,在这里都是理所当然的东西。
被否定、被遗忘、成为幻想之物的归宿,那就是幻想乡。
在这里,人类仍然敬畏神明,仍然谈论着魍魉魑魅。
巫女能在空中飞行也好、吸血鬼释放出血红雾气也好、冬天和夜晚不会结束也好、某位圣人突然复活也好……
妖怪等非人之物掀起异变、人类中的英雄前去应对,这便是幻想乡的日常。



---------------------------------------------------------------------------

PermissionError                           Traceback (most recent call last)

d:\Code\py\test\design\1.ipynb 单元格 17 line 6
     <a href='vscode-notebook-cell:/d%3A/Code/py/test/design/1.ipynb#X22sZmlsZQ%3D%3D?line=59'>60</a> subjp = ProtectedProxy("mini.txt")
     <a href='vscode-notebook-cell:/d%3A/Code/py/test/design/1.ipynb#X22sZmlsZQ%3D%3D?line=60'>61</a> print(subjp.get())
---> <a href='vscode-notebook-cell:/d%3A/Code/py/test/design/1.ipynb#X22sZmlsZQ%3D%3D?line=61'>62</a> subjp.set("123")


d:\Code\py\test\design\1.ipynb 单元格 17 line 5
     <a href='vscode-notebook-cell:/d%3A/Code/py/test/design/1.ipynb#X22sZmlsZQ%3D%3D?line=56'>57</a> def set(self,c):
---> <a href='vscode-notebook-cell:/d%3A/Code/py/test/design/1.ipynb#X22sZmlsZQ%3D%3D?line=57'>58</a>     raise PermissionError


PermissionError: 

享元模式(Flyweight Pattern)

主要用于减少创建对象的数量,以减少内存占用和提高性能。提供了减少对象数量从而改善应用所需的对象结构的方式。
意图:运用共享技术有效地支持大量细粒度的对象。

主要解决:在有大量对象时,有可能会造成内存溢出,我们把其中共同的部分抽象出来,如果有相同的业务请求,直接返回在内存中已有的对象,避免重新创建。

何时使用: 1、系统中有大量对象。 2、这些对象消耗大量内存。 3、这些对象的状态大部分可以外部化。 4、这些对象可以按照内蕴状态分为很多组,当把外蕴对象从对象中剔除出来时,每一组对象都可以用一个对象来代替。 5、系统不依赖于这些对象身份,这些对象是不可分辨的。

如何解决:用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象。

关键代码:用 HashMap 存储这些对象。

应用实例: 1、JAVA 中的 String,如果有则返回,如果没有则创建一个字符串保存在字符串缓存池里面。 2、数据库的连接池。

优点:大大减少对象的创建,降低系统的内存,使效率提高。

缺点:提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,不应该随着内部状态的变化而变化,否则会造成系统的混乱。

使用场景: 1、系统有大量相似对象。 2、需要缓冲池的场景。

注意事项: 1、注意划分外部状态和内部状态,否则可能会引起线程安全问题。 2、这些类必须有一个工厂对象加以控制。

from abc import ABCMeta,abstractmethod
class Item(metaclass=ABCMeta):
    @abstractmethod
    def show(self):
        pass

class Computer(Item):
    def __init__(self,name,storage=None) -> None:
        self.name = name
        self.storage = storage
    
    def show(self):
        print(f"{self.name} 's storage is' {self.storage} G")

    def setStorage(self,s):
        self.storage = s
    
class ComputerFactory:
    def __init__(self) -> None:
        self.map = dict()
    
    def getComputer(self,name):
        if name in self.map:
            return self.map[name]
        else:
            ret = Computer(name)
            self.map[name] = ret
            return ret
    
# client
fac = ComputerFactory()
c1 = fac.getComputer("apple")
print(id(c1))
c1.setStorage(5)
c1.show()
c2 = fac.getComputer("dell")
print(id(c2))
c3 = fac.getComputer("apple")
print(id(c3))
c3.setStorage(8)
c3.show()
1451231440400
apple 's storage is' 5 G
1451231464208
1451231440400
apple 's storage is' 8 G

行为型模式

责任链模式

内容: 使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
发送者和接受者之间的耦合关系:例如直接在高层模块中出现大量的if else
抽象处理者,具体处理者,客户端

多个对象处理一个请求
不明确接受者情况下,向其中一个提交请求
减少耦合

# 例如marisa挑战东方妖妖梦try ver
from abc import ABCMeta,abstractmethod
class Handle(metaclass=ABCMeta):
    @abstractmethod
    def handle_stage(self,live):
        pass

class whiterock(Handle):
    def __init__(self) -> None:
        self.next = chen()
    def handle_stage(self, live):
        if live <= 1:
            print("end")
        else:
            print("pass")
            self.next.handle_stage(live)

class chen(Handle):
    def __init__(self) -> None:
        self.next = alice()
    def handle_stage(self, live):
        if live <= 3:
            print("end")
        else:
            print("pass")
            self.next.handle_stage(live)

class alice(Handle):
    def handle_stage(self, live):
        if live <= 5:
            print("end")
        else:
            print("end and game success")
# client
day = 4
h = whiterock()
h.handle_stage(day)
pass
pass
end

观察者模式

内容:定义对象间的一种 一对多 的依赖关系
当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。观察者模式又称“发布-订阅”模式
发布者更新后,高层模块不需要再额外if else。
bind and unbind 方便,即不能紧耦合

抽象主题 (Subject)
具体主题-发布者(Concrete Subject)
抽象观察者 (Observer)
具体观察者-订阅者(Concrete Observer)

对象的改变需要同时改变其它对家,而不知道具体有多对象有待改变
一个对象必须通知其它对象,而它又不能假定其它对象是谁。换言之,你不希望这些对象是紧密耦合的

目标和观察者之间的抽象耦合最小
支持广播通信

from abc import ABCMeta,abstractmethod
class Observer(metaclass=ABCMeta):
    @abstractmethod
    def update(self):
        """
        一旦有notice时,我进行更新
        """
        pass

class Notice:
    def __init__(self) -> None:
        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) -> 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()       # vital!!!

class Staff(Observer):
    def __init__(self) -> None:
        self.now_info = None
    
    def update(self,notice):
        self.now_info = notice.company_info
        
#client
notice = StaffNotice()
s1 = Staff()
s2 = Staff()
notice.attach(s1)
notice.attach(s2)
print(s1.now_info)
print(s2.now_info)
notice.company_info = "hello world"
print(s1.now_info)
notice.detach(s1)
notice.company_info = "hi1"
print(s1.now_info)
None
None
hello world
hello world

策略模式

内容:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。
抽象策略,具体策略,上下文
例如,打车软件,在服务器空闲时使用最优的算法,在拥挤时使用次优算法
策略切换

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

from abc import ABCMeta,abstractmethod
class Strategy(metaclass=ABCMeta):
    @abstractmethod
    def execute(self,data):
        pass

class FastStrategy(Strategy):
    def execute(self, data):
        print("rapid exec dataing!")

class SlowStrategy(Strategy):
    def execute(self, data):
        print("slow execing !")

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

    def setStrategy(self,strategy):
        # switch strategy
        self.strategy = strategy
    
    def doStrategy(self):
        self.strategy.execute(self.data)

# client
data = 123
s = FastStrategy()
c = Context(data,s)
c.doStrategy()
c.setStrategy(SlowStrategy())
c.doStrategy()
rapid exec dataing!
slow execing !

模板方法模式

内容:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步聚
抽象类 (AbstractClass)定义抽象的原子操作(钩子操作) ;实现一个模板方法作为算法的骨架
具体类 (ConcreteClass)实现原子操作

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

from abc import ABCMeta,abstractmethod
from time import sleep

class Window(metaclass = ABCMeta):
    """
    知道抽象类需要这些
    """
    @abstractmethod
    def start(self):
        pass
    @abstractmethod
    def repaint(self):
        pass
    @abstractmethod
    def close(self):
        # 原子操作/钩子操作
        pass

    def run(self):
        # 模板方法
        self.start()
        while True:
            try:
                self.repaint()
                sleep(1)
            except KeyboardInterrupt:
                break
        self.close()

class mywindow(Window):
    def __init__(self,msg) -> None:
        self.msg = msg
    def start(self):
        print("start")
    def close(self):
        print("end")
    def repaint(self):
        print(self.msg)

mywindow("hello").run()
start
hello
hello
hello
end

命令模式

https://www.runoob.com/design-pattern/command-pattern.html
将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。
何时使用:在某些场合,比如要对行为进行"记录、撤销/重做、事务"等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将"行为请求者"与"行为实现者"解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。

如何解决:通过调用者调用接受者执行命令,顺序:调用者→命令→接受者。
1、received 真正的命令执行对象 2、Command 3、invoker 使用命令对象的入口

from abc import ABCMeta,abstractmethod
# 命令接口
class Order(metaclass=ABCMeta):
    @abstractmethod
    def execute(self):
        pass

# 创建请求类
# receiver
class Stock:
    def __init__(self,name,quantity) -> None:
        self.name = name
        self.quantity = quantity
    
    def buy(self):
        print(f"{self.name} bought, quantity is {self.quantity}")

    def sell(self):
        print(f"{self.name} sell, quantity is {self.quantity}")
    
# 实现order接口
class buyStock(Order):
    def __init__(self,stock):
        self.stock = stock
    
    def execute(self):
        self.stock.buy()
    
class sellStock(Order):
    def __init__(self,stock):
        self.stock = stock
    
    def execute(self):
        self.stock.sell()
        pass

# invoker
class Tool:
    def __init__(self) -> None:
        self.orderList = []
    
    def add(self,order):
        self.orderList.append(order)
    
    def exec(self):
        for job in self.orderList:
            job.execute()
        self.orderList.clear()

j = Tool()
s1 = Stock("reimu",10)
s2 = Stock("marisa",15)
j.add(sellStock(s1))
j.add(buyStock(s2))
j.exec()
reimu sell, quantity is 10
marisa bought, quantity is 15

访问者模式

https://www.runoob.com/design-pattern/visitor-pattern.html
意图:主要将数据结构与数据操作分离。
主要解决:稳定的数据结构和易变的操作耦合问题。
何时使用:需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免让这些操作"污染"这些对象的类,使用访问者模式将这些封装到类中。
如何解决:在被访问的类里面加一个对外提供接待访问者的接口。
关键代码:在数据基础类里面有一个方法接受访问者,将自身引用传入访问者。

数据访问对象

前端控制模式

前端控制器模式(Front Controller Pattern)是用来提供一个集中的请求处理机制,所有的请求都将由一个单一的处理程序处理。该处理程序可以做认证/授权/记录日志,或者跟踪请求,然后把请求传给相应的处理程序。以下是这种设计模式的实体。

前端控制器(Front Controller) - 处理应用程序所有类型请求的单个处理程序,应用程序可以是基于 web 的应用程序,也可以是基于桌面的应用程序。
调度器(Dispatcher) - 前端控制器可能使用一个调度器对象来调度请求到相应的具体处理程序。
视图(View) - 视图是为请求而创建的对象。

from abc import ABCMeta,abstractmethod
import re
class View(metaclass=ABCMeta):
    @abstractmethod
    def show(self):
        pass

class HomeView(View):
    def show(self):
        print("Home Viewer show")

class PageView(View):
    def show(self):
        print("Page Viewer show")

class Dispatcher:
    homeview = HomeView()
    pageview = PageView()
    def dispatch(self,request:str):
        if re.match("home",request,re.I) is not None:
            self.homeview.show()
        elif re.match("page",request,re.I) is not None:
            self.pageview.show()

class frontControl:
    def __init__(self,dispatcher) -> None:
        self.dispatcher = dispatcher
        pass
    def isAuth(self)->bool:
        return True
    def trackrequest(self,request:str):
        print(f"TRACK REQUEST {request}")
    def dispatchRequest(self,request:str):
        if self.isAuth() is True:
            self.trackrequest(request=request)
            self.dispatcher.dispatch(request)

tool = frontControl(Dispatcher())
tool.dispatchRequest("home")
tool.dispatchRequest("PaGe")
    
TRACK REQUEST home
Home Viewer show
TRACK REQUEST PaGe
Page Viewer show

拦截过滤器模式

对应用程序的请求或响应做一些预处理/后处理。定义过滤器,并在把请求传给实际目标应用程序之前应用在请求上。过滤器可以做认证/授权/记录日志,或者跟踪请求,然后把请求传给相应的处理程序。以下是这种设计模式的实体。
过滤器(Filter) - 过滤器在请求处理程序执行请求之前或之后,执行某些任务。
过滤器链(Filter Chain) - 过滤器链带有多个过滤器,并在 Target 上按照定义的顺序执行这些过滤器。
Target - Target 对象是请求处理程序。
过滤管理器(Filter Manager) - 过滤管理器管理过滤器和过滤器链。
客户端(Client) - Client 是向 Target 对象发送请求的对象

from abc import ABCMeta,abstractmethod

# abstract filter
class Filter(abstractmethod):
    @abstractmethod
    def execute(self,request):
        pass

# concrete filter
class AuthFilter(Filter):
    def execute(self,request):
        print(f"AUTH in {request}")

class LogFilter(Filter):
    def execute(self, request):
        print(f"LOG {request}")

# Target
class Target:
    def execute(self,request):
        print("parser>" , request)

# Filter Chain
class FilterChain:
    B = 0
    A = 1
    def __init__(self) -> None:
        self.preFilters = []
        self.postFilters = []
        self.target = None
    def addFilter(self,f:Filter,pos):
        if pos == self.B:
            self.preFilters.append(f)
        else:
            self.postFilters.append(f)

    def execute(self,request):
        for filter in self.preFilters:
            filter.execute(request)
        self.target.execute(request)
        for filter in self.postFilters:
            filter.execute(request)

    def setTarget(self,target):
        self.target = target

# Filter Manager
class FilterManager:
    def __init__(self,target) -> None:
        self.chain = FilterChain()
        self.chain.setTarget(target)
    
    def setFilter(self):
        return self.chain   #  偷懒
    
    def TargetRequest(self,request):
        self.chain.execute(request) 

0 评论:

发表评论