【Python笔记-设计模式】访问者模式

一、说明

访问者模式是一种行为设计模式,它能在不改变元素类的情况下定义对元素对象的新操作

(一) 解决问题

将算法与对象结构分离,使得算法可以独立于对象结构而变化。主要解决在不改变对象结构的前提下,增加新的操作或功能

(二) 使用场景

  • 对象结构中的元素需要不同方式的操作,并且这些操作需要相互独立,不影响元素类的稳定性和扩展性。
  • 对象结构中的元素类经常变化,但是需要为对象结构中的元素添加新的操作。
  • 需要对一个对象结构中的元素进行复杂的、多变的操作,而不希望这些操作污染元素类。

二、结构

  1. 访问者(Visitor)接口声明了一系列以对象结构的具体元素为参数的访问者方法。如果编程语言支持重载,这些方法的名称可以是相同的,但是其参数一定是不同的。
  2. 具体访问者(ConcreteVisitor)会为不同的具体元素类实现相同行为的几个不同版本。
  3. 元素(Element)接口声明了一个方法来“接收”访问者。该方法必须有一个参数被声明为访问者接口类型。
  4. 具体元素(ConcreteElement)必须实现接收方法。该方法的目的是根据当前元素类将其调用重定向到相应访问者的方法。请注意,即使元素基类实现了该方法,所有子类都必须对其进行重写并调用访问者对象中的合适方法。
  5. 客户端(Client)通常会作为集合或其他复杂对象(例如一个组合树)的代表。客户端通常不知晓所有的具体元素类,因为它们会通过抽象接口与集合中的对象进行交互。

三、伪代码

#!/usr/bin/env python
# -*- coding: UTF-8 -*-
__doc__ = """
访问者模式

例:病人(元素类)有两种类型:急诊病人和住院病人。医生和护士(访问者)对不同类型的病人进行不同的操作。
通过访问者模式,可以实现对病人的管理和处理,而不需要修改病人类的代码。
"""

from abc import ABC, abstractmethod


class Patient(ABC):
    """元素基类(病人基类)"""
    @abstractmethod
    def accept(self, visitor):
        pass


class EmergencyPatient(Patient):
    """元素具体类(急诊病人)"""
    def accept(self, visitor):
        visitor.visit_emergency_patient(self)


class Inpatient(Patient):
    """元素具体类(住院病人)"""
    def accept(self, visitor):
        visitor.visit_inpatient(self)


class Visitor(ABC):
    """访问者基类"""
    @abstractmethod
    def visit_emergency_patient(self, patient):
        pass

    @abstractmethod
    def visit_inpatient(self, patient):
        pass


class Doctor(Visitor):
    """具体访问者,医生类"""
    def visit_emergency_patient(self, patient):
        print(f"医生对急诊病人 {patient} 进行检查和治疗。")

    def visit_inpatient(self, patient):
        print(f"医生对住院病人 {patient} 进行观察和治疗。")


class Nurse(Visitor):
    """具体访问者,护士类"""
    def visit_emergency_patient(self, patient):
        print(f"护士对急诊病人 {patient} 进行急救和护理。")

    def visit_inpatient(self, patient):
        print(f"护士对住院病人 {patient} 进行护理和照顾。")


if __name__ == "__main__":
    """
        医生对急诊病人 <__main__.EmergencyPatient object at 0x104e46ac0> 进行检查和治疗。
        护士对急诊病人 <__main__.EmergencyPatient object at 0x104e46ac0> 进行急救和护理。
        医生对住院病人 <__main__.Inpatient object at 0x104e46a30> 进行观察和治疗。
        护士对住院病人 <__main__.Inpatient object at 0x104e46a30> 进行护理和照顾。
    """
    patients = [EmergencyPatient(), Inpatient()]
    doctor = Doctor()
    nurse = Nurse()

    for patient in patients:
        patient.accept(doctor)
        patient.accept(nurse)

四、优缺点

优点

  • 开闭原则:你可以引入在不同类对象上执行的新行为,且无需对这些类做出修改。
  • 单一职责原则:可将同一行为的不同版本移到同一个类中。

缺点

  • 增加新的元素类很困难,因为需要修改所有的访问者类
  • 访问者模式要求具有稳定的对象结构,如果对象结构经常变化,则会导致访问者类的频繁修改,不利于系统的维护和扩展。
  • 访问者模式会使代码变得更加复杂,因为它引入了额外的类和接口,增加了系统的抽象性和理解难度

【Python笔记】设计模式-CSDN博客