首页 > 编程语言 >使用方法重载实现Python访问者模式

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

时间:2024-12-16 20:53:14浏览次数:7  
标签:name Python self visit cat 重载 def 访问者

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方法,将抛出异常。

标签:name,Python,self,visit,cat,重载,def,访问者
From: https://www.cnblogs.com/linsuiyuan/p/18611099

相关文章

  • Python程序设计——实验与实践
    三、PY_03_03PY_03_06PY_03_07四、PY_04_02PY_04_03PY_04_05PY_04_07PY_04_08......
  • 用Python实现交换元素使之倒叙输出(4种方法)
    好久没更新了嘿嘿,今天多更一些方法【练习要求】针对知识点使用for循环、列表下标、格式化字符串安排的本实例。要求实现交换列表元素的位置,实现效果如下:方法一:list1=[1,3,5,7,9]print(list1)list1.reverse()print(list1)直接用reverse()倒序输出的语法(好像不算交......
  • MA1CANU Python Programming
    CALCULUS(MA1CANU)PythonProgrammingAssignmentThisassignmentcountsfor20%ofthetotalmarksofthismodule.FullmarksforthisassignmentcanbegainedfromcompleteanswerstoALLquestionsandsubmittingthePythonscript.pyforeachquestionso......
  • python opencv车牌图像校正
    车牌图片代码#-*-coding:UTF-8-*-importcv2importnumpyasnp#预处理defimgProcess(path):img=cv2.imread(path)#统一规定大小img=cv2.resize(img,(640,480))#高斯模糊img_Gas=cv2.GaussianBlur(img,(5,5),0)#RGB......
  • Python 删除Word中的表格
    在处理Word文档时,我们经常会遇到需要删除表格的情况。无论是为了简化文档结构,还是为了更新内容,删除表格都是一个常见的操作。但是通过手动删除不仅耗时,而且容易出错,本文将介绍如何使用Python通过编程删除Word中的表格。Python删除Word中的指定表格Python删除Word中的所有表格......
  • 【华为OD-E卷-ai面板识别 100分(python、java、c++、js、c)】
    【华为OD-E卷-ai面板识别100分(python、java、c++、js、c)】题目AI识别到面板上有N(1≤N≤100)个指示灯,灯大小一样,任意两个之间无重叠。由于AI识别误差,每次别到的指示灯位置可能有差异,以4个坐标值描述AI识别的指示灯的大小和位置(左上角x1,y1,右下角x2,y2),请输出先行后......
  • Python 文件查重工具
    Python文件查重工具——循环删除重复文件1.简介:这是一个Python文件去重的工具,市面上很多检测重复工具的软件,都是要付费或者要破解的。于是就想着能不能自己做一个后台每时每刻都可以自己去重的工具。虽然市面上很多检测重复工具的软件.但是这个工具使用环境和那些工具......
  • Python生成雪花、代码雨、绝美圣诞树!?
    下面给大家发一些有趣不知道的Python代码,超级有趣,快去试试!日常放松一下,给爱的人发过去吧!1、绘制分形图形(以科赫雪花为例)importturtledefkoch(t,order,size):iforder==0:t.forward(size)else:foranglein[60,-120,60,0]:......
  • python:文档测试
    在Python中,文档测试(doctest)是一种通过嵌入示例代码和预期输出来测试文档字符串(docstrings)和文档中的代码片段的方法。它允许开发者在编写文档的同时,确保文档中的代码示例是准确和有效的。doctest模块会读取文档字符串或指定文件中的代码示例,执行它们,并比较实际输出与预期输出。......
  • python:单元测试
    在Python编程中,单元测试是确保代码按预期工作的关键步骤之一。单元测试是指对代码中的最小可测试单元(通常是函数或方法)进行隔离测试,以验证其行为是否符合预期。Python有一个内置的单元测试框架,名为unittest,它提供了编写和运行测试所需的所有工具。使用unittest编写单元测试以......