Python使用方法重载实现访问者模式

 更新时间:2024年12月17日 10:23:28   作者:三叔木卯  
这篇文章主要为大家详细介绍了Python如何使用方法重载实现访问者模式,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

Python上的访问者模式,看了一下网上其他人的例子,一般都是类似下面的代码。

from abc import ABC, abstractmethod  
  
# 抽象访问者  
class AnimalVisitor(ABC):  
    @abstractmethod  
    def visit_dog(self, dog: "Dog"):  
        pass  
  
    @abstractmethod  
    def visit_cat(self, cat: "Cat"):  
        pass  
  
# 抽象动物类  
class Animal(ABC):  
    def __init__(self, name: str):  
        self.name = name  
  
    @abstractmethod  
    def accept(self, visitor: AnimalVisitor):  
        pass  
  
# 具体动物类  
class Dog(Animal):  
    def accept(self, visitor):  
        visitor.visit_dog(self)  
  
class Cat(Animal):  
    def accept(self, visitor):  
        visitor.visit_cat(self)  
  
# 具体访问者:喂食访问者  
class FeedingVisitor(AnimalVisitor):  
    def visit_dog(self, dog):  
        print(f"给{dog.name}喂狗粮")  
  
    def visit_cat(self, cat):  
        print(f"给{cat.name}喂猫粮")  
  
# 具体访问者:检查健康访问者  
class HealthCheckVisitor(AnimalVisitor):  
    def visit_dog(self, dog):  
        print(f"检查{dog.name}的疫苗接种情况")  
  
    def visit_cat(self, cat):  
        print(f"检查{cat.name}是否需要洗澡")

使用示例如下:

def main():  
    # 创建动物  
    dog = Dog("旺财")  
    cat = Cat("咪咪")  
  
    # 创建访问者  
    feeding_visitor = FeedingVisitor()  
    health_visitor = HealthCheckVisitor()  
  
    # 创建动物列表  
    animals = [dog, cat]  
  
    # 执行不同的操作  
    print("=== 喂食时间 ===")  
    for animal in animals:  
        animal.accept(feeding_visitor)  
  
    print("\n=== 健康检查 ===")  
    for animal in animals:  
        animal.accept(health_visitor)
  
  
if __name__ == "__main__":  
    main()

以上实现的访问者模式,访问者的接口类(抽象类)一般通过定义不同的方法(带visit前缀的方法)来对不同的被访问者进行访问。有些奇怪,为什么不通过方法重载的方式来实现访问者模式呢?

通过定义不同方法来实现访问者模式,明显违背一些设计原则的。访问者的接口类需要负责访问不同方法,而这些方法之间相关性不大(删除某个方法对其他方法没有影响),这明显违背了单一职责原则(SRP);如果要添加一种动物(被访问者),那么就要修改访问者接口类以添加相应的方法,这是违背开闭原则(OCP)的;访问者的接口类的方法还依赖了具体类(比如DogCat类),这违背了依赖倒转原则(DIP)

使用方法重载实现的访问者模式,则没有上面的问题,而且代码也更简单明了。Python没有传统的方法重载方式,不过在functools模块里有个singledispatchmethod单分派装饰器,这里可以借用它来实现“方法重载”。

使用方法重载的方式代码如下:

from abc import ABC, abstractmethod  
from functools import singledispatchmethod  
  
# 抽象访问者  
class AnimalVisitor(ABC):  
    @abstractmethod  
    def visit(self, animal: "Animal"):  
        pass  
  
# 抽象动物类  
class Animal(ABC):  
    def __init__(self, name: str):  
        self.name = name  
  
    def accept(self, visitor: AnimalVisitor):  
        visitor.visit(self)  
  
# 具体动物类  
class Dog(Animal): ...  
  
class Cat(Animal): ...  
  
# 具体访问者:喂食访问者  
class FeedingVisitor(AnimalVisitor):  
    @singledispatchmethod  
    def visit(self, animal: Animal):  
        raise NotImplementedError(f"{type(animal)} 未重载 visit方法")  
  
    @visit.register(Dog)  
    def _(self, dog):  
        print(f"给{dog.name}喂狗粮")  
  
    @visit.register(Cat)  
    def _(self, cat):  
        print(f"给{cat.name}喂猫粮")  
  
# 具体访问者:检查健康访问者  
class HealthCheckVisitor(AnimalVisitor):  
  
    @singledispatchmethod  
    def visit(self, animal: Animal):  
        raise NotImplementedError(f"{type(animal)} 未重载 visit方法")  
  
    @visit.register(Dog)  
    def _(self, dog):  
        print(f"检查{dog.name}的疫苗接种情况")  
  
    @visit.register(Cat)  
    def _(self, cat):  
        print(f"检查{cat.name}是否需要洗澡")

可以看到,这一种方式访问者抽象类AnimalVisitor的方法只有一个,就是visitAnimalVisitor只负责一个职责,那就是访问动物,符合单一职责原则;添加其他种动物的时候,不用修改抽象类,符合开闭原则AnimalVisitor现在只依赖Animal这个抽象类,符合依赖倒转原则

有人可能担心,如果访问者抽象类没有把访问动物类的相应方法都列出来,会导致具体访问者类漏实现一些方法重载。这个问题在上面的代码中考虑到了,在singledispatchmethod装饰的visit方法里使用NotImplementedError异常进行防御,如果某个具体动物类没有重载visit方法,将抛出异常。

到此这篇关于Python使用方法重载实现访问者模式的文章就介绍到这了,更多相关Python访问者模式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • YOLOv5车牌识别实战教程(三)模型训练与评估

    YOLOv5车牌识别实战教程(三)模型训练与评估

    这篇文章主要介绍了YOLOv5车牌识别实战教程(三)模型训练与评估,在这个教程中,我们将一步步教你如何使用YOLOv5进行车牌识别,帮助你快速掌握YOLOv5车牌识别技能,需要的朋友可以参考下
    2023-04-04
  • Python基于pandas爬取网页表格数据

    Python基于pandas爬取网页表格数据

    这篇文章主要介绍了Python基于pandas获取网页表格数据,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-05-05
  • Python设计模式之迭代器模式原理与用法实例分析

    Python设计模式之迭代器模式原理与用法实例分析

    这篇文章主要介绍了Python设计模式之迭代器模式原理与用法,结合具体实例形式分析了迭代器模式的概念、原理、定义及使用方法,代码注释说明简单易懂,需要的朋友可以参考下
    2019-01-01
  • PyG搭建GCN需要准备的数据格式

    PyG搭建GCN需要准备的数据格式

    这篇文章主要为大家介绍了PyG搭建GCN前需要准备的PyG数据格式,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • Python+Pillow+Pytesseract实现验证码识别

    Python+Pillow+Pytesseract实现验证码识别

    这篇文章主要为大家详细介绍了如何利用pillow和pytesseract来实现验证码的识别,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一下
    2022-05-05
  • Python稀疏矩阵及参数保存代码实现

    Python稀疏矩阵及参数保存代码实现

    这篇文章主要介绍了Python稀疏矩阵及参数保存代码实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-04-04
  • Python PyQt5中弹出子窗口解决子窗口一闪而过的问题

    Python PyQt5中弹出子窗口解决子窗口一闪而过的问题

    这篇文章主要介绍了Python PyQt5中弹出子窗口解决子窗口一闪而过的问题,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • Jmeter中JSR223设置变量方式

    Jmeter中JSR223设置变量方式

    本文主要介绍了JMeter的几种常用变量设置方式,特别对JSR223设置变量进行了详细解释,JSR223是Java规范请求,可以向Java平台增添新的API和服务,JSR223Sampler可以使用JSR223脚本代码执行创建/更新变量所需的示例或一些计算
    2024-10-10
  • keras:model.compile损失函数的用法

    keras:model.compile损失函数的用法

    这篇文章主要介绍了keras:model.compile损失函数的用法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-07-07
  • python 使用递归的方式实现语义图片分割功能

    python 使用递归的方式实现语义图片分割功能

    这篇文章主要介绍了python 使用递归的方式实现语义图片分割,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-07-07

最新评论