📜  访问者方法 - Python设计模式(1)

📅  最后修改于: 2023-12-03 15:28:09.062000             🧑  作者: Mango

访问者方法 - Python设计模式

访问者方法是一种行为型设计模式,它允许你在不修改对象结构的前提下,为对象结构中的元素添加新功能。该模式可以用于在运行时进行任意类型的操作,但其中的元素必须明确知道如何接收来自访问者的请求。

应用场景

访问者模式适用于以下场景:

  1. 当需要对一组对象进行复杂操作时,而不希望影响对象间的结构时,可以使用访问者方法。该方法将复杂操作从对象结构中分离出来,使得对象结构可以保持原有的接口;
  2. 当代码中有大量的逻辑判断,而这些逻辑又需要不断地添加和修改时,可以考虑使用访问者方法。该方法可以将逻辑判断从元素中分离出来,使得后续的维护变得简单;
  3. 当对象结构中的元素需要经常发生变化时,可以使用访问者方法。该方法可以避免对对象结构中的元素直接添加新功能,而是将新功能封装在一个访问者中,便于扩展。
示例代码

以下是一个示例代码,它展示了访问者方法的使用方式:

from abc import ABC, abstractmethod


class Element(ABC):
    @abstractmethod
    def accept(self, visitor):
        pass


class ConcreteElementA(Element):
    def accept(self, visitor):
        visitor.visit_concrete_element_a(self)

    def operation_a(self):
        print("Operation A of ConcreteElementA")


class ConcreteElementB(Element):
    def accept(self, visitor):
        visitor.visit_concrete_element_b(self)

    def operation_b(self):
        print("Operation B of ConcreteElementB")


class Visitor(ABC):
    @abstractmethod
    def visit_concrete_element_a(self, element: ConcreteElementA):
        pass

    @abstractmethod
    def visit_concrete_element_b(self, element: ConcreteElementB):
        pass


class ConcreteVisitor1(Visitor):
    def visit_concrete_element_a(self, element: ConcreteElementA):
        print("ConcreteVisitor1: visiting ConcreteElementA")
        element.operation_a()

    def visit_concrete_element_b(self, element: ConcreteElementB):
        print("ConcreteVisitor1: visiting ConcreteElementB")
        element.operation_b()


class ConcreteVisitor2(Visitor):
    def visit_concrete_element_a(self, element: ConcreteElementA):
        print("ConcreteVisitor2: visiting ConcreteElementA")
        element.operation_a()

    def visit_concrete_element_b(self, element: ConcreteElementB):
        print("ConcreteVisitor2: visiting ConcreteElementB")
        element.operation_b()


class ObjectStructure:
    def __init__(self):
        self._elements = []

    def attach(self, element):
        self._elements.append(element)

    def detach(self, element):
        self._elements.remove(element)

    def accept(self, visitor):
        for element in self._elements:
            element.accept(visitor)


if __name__ == '__main__':
    object_structure = ObjectStructure()
    object_structure.attach(ConcreteElementA())
    object_structure.attach(ConcreteElementB())
    object_structure.accept(ConcreteVisitor1())
    object_structure.accept(ConcreteVisitor2())

以上示例代码中,我们定义了访问者类、元素类和对象结构类。在这个示例中,元素类有两个:ConcreteElementA和ConcreteElementB。每个元素都可以接受不同的访问者(ConcreteVisitor1和ConcreteVisitor2),并执行不同的操作。对象结构类负责维护所有元素,并且通过accept方法接受不同的访问者。

优缺点
优点
  1. 容易扩展:当需要对元素执行新操作时,可以很容易地创建新的访问者,这样就可以为元素添加新功能,而不需要修改元素或者其他元素的代码;
  2. 当元素结构不变时,可以很容易地在不同的元素上执行不同的操作;
  3. 通过将访问者逻辑从元素代码中分离出来,可以遵循单一职责原则,让代码更加清晰。
缺点
  1. 增加代码的复杂度:使用访问者模式会增加代码的复杂度,这是因为访问者模式还需要再元素类中定义访问者方法,并确保访问者可以通过元素的接口进行访问;
  2. 不符合开闭原则:每次新增一个元素时,需要为该元素定义访问者方法,这会导致元素类的改动。这违反了开闭原则中的"对扩展开放,对修改关闭"。