1. 简介
访问者模式(Visitor Pattern)是一种行为型设计模式,我们可以使用它将操作(访问者)与其所操作的对象结构分离。通过这种方式,我们可以在不修改操作对象结构的前提下,定义作用于这些对象的新操作。
2. 模式结构
classDiagram
class Client {
+main()
}
class Visitor {
<<interface>>
+visit(element: Element)
}
class Element {
<<interface>>
+accept(visitor: Visitor)
}
class ConcreteElement1 {
+accept(visitor: Visitor)
}
class ConcreteElement2 {
+accept(visitor: Visitor)
}
class ConcreteVisitor {
+visitConcreteElement1(elem: ConcreteElement1)
+visitConcreteElement2(elem: ConcreteElement2)
}
class ObjectStructure {
-elements: List[Element]
+add(element: Element)
+remove(element: Element)
+accept(visitor: Visitor)
}
Client ..> ObjectStructure
Client ..> ConcreteVisitor
Client ..> ConcreteElement1
Client ..> ConcreteElement2
Element <|.. ConcreteElement1
Element <|.. ConcreteElement2
Visitor <|.. ConcreteVisitor
ConcreteVisitor ..> ConcreteElement1
ConcreteVisitor ..> ConcreteElement2
ObjectStructure o-- Element
ObjectStructure ..> Visitor
- Visitor(访问者):定义一个访问具体元素的方法接口,为每一个具体元素类对应一个访问方法。
- ConcreteVisitor(具体访问者):实现 Visitor 接口,为每个具体元素类实现相应的访问方法。
- Element(元素):定义一个接受访问操作的方法接口,接受一个访问者对象。
- ConcreteElement(具体元素):实现 Element 接口,实现 accept 方法,该方法调用访问者的访问方法。
- Object Structure(对象结构): 包含元素的集合,可以是一个列表、一个集合或者其他数据结构。负责遍历元素,并调用元素的接受方法。
- Client(客户端):调用具体访问者以及具体元素来实现业务功能。
3. 优缺点以及使用场景
优点
-
扩展性好:可以在不修改对象结构的情况下增加新的操作。新增操作时,只需增加新的访问者类,而不需要改变现有的元素类。
-
复用性好:通过访问者模式可以将无关的操作分离,使得操作更加单一和独立。
-
简化操作类的定义:通过集中处理,使得可以简化操作类的定义,从而使得每个操作类的逻辑更加清晰。
-
符合单一职责原则:每个访问者都负责一个特定的操作,从而符合单一职责原则,便于管理和维护。
缺点
-
破坏封装:访问者模式通常需要访问对象的内部细节,可能会破坏对象的封装性。元素类需要暴露一些细节给访问者,使得访问者可以访问它们。
-
复杂性增加:对象结构和访问者的定义可能会变得复杂,特别是当对象结构和访问者的数量增加时。
使用场景
- 当一个对象结构包含多种类型的元素,且需要对这些元素执行很多不相关的操作,而不想让这些操作“污染”这些元素的类时。
- 当该对象结构被很多应用共享,而想为每个应用提供在该结构上的个性化行为时。
访问者模式在图形界面库、编译器前端、代码分析工具等领域有广泛应用,它能够很好地处理需要对复杂对象结构进行遍历并执行特定操作的场景。
4. 示例:【设计模式专题之访问者模式】23-图形的面积
"""
【设计模式专题之访问者模式】23-图形的面积
时间限制:1.000S 空间限制:256MB
题目描述
小明家有一些圆形和长方形面积的土地,请你帮他实现一个访问者模式,使得可以通过访问者计算每块土地的面积。
图形的面积计算规则如下:
圆形的面积计算公式为:3.14 * 半径 * 半径
矩形的面积计算公式为:长 * 宽
输入描述
第一行是一个整数 n(1 <= n <= 1000),表示图形的数量。
接下来的 n 行,每行描述一个图形,格式为 "Circle r" 或 "Rectangle width height",其中 r、width、height 是正整数。
输出描述
对于每个图形,输出一行,表示该图形的面积。
输入示例
3
Circle 5
Rectangle 3 4
Circle 2
输出示例
78.5
12
12.56
"""
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def calcArea(self, calculator: "Calculator"):
raise NotImplemented
class Circle(Shape):
def __init__(self, radius: int):
self.radius = radius
def calcArea(self, calculator: "Calculator"):
calculator.calcCirArea(self)
class Rectangle(Shape):
def __init__(self, width: int, height: int):
self.width = width
self.height = height
def calcArea(self, calculator: "Calculator"):
calculator.calcRectArea(self)
class Calculator:
def calcCirArea(self, circle: Circle):
area = 3.14 * circle.radius * circle.radius
print(round(area, 2))
def calcRectArea(self, rect: Rectangle):
area = rect.width * rect.height
print(round(area, 2))
def client():
n = int(input())
calculator = Calculator()
for _ in range(n):
args = input().split()
if len(args) == 2:
radius = int(args[-1])
shape = Circle(radius)
else:
assert len(args) == 3
width = int(args[1])
height = int(args[-1])
shape = Rectangle(width, height)
shape.calcArea(calculator)
if __name__ == "__main__":
client()