设计模式 - 访问者模式
访问者模式(Visitor Pattern)允许你在不修改对象结构的情况下,增加新的操作。这就像是你通过一个“访问者”对象来访问一组元素,执行各种操作 。
访问者模式的核心角色:
- 元素(Element):所有需要被访问的类,通常有一个
accept()
方法,用来接受访问者的访问。 - 具体元素(ConcreteElement):元素类的具体实现,它实现了
accept()
方法,通常会将访问者传递到具体的处理方法。 - 访问者(Visitor):定义所有访问方法,每个访问方法对应一种元素类型。
- 具体访问者(ConcreteVisitor):实现具体操作,如何访问元素并执行相应的动作。
核心思想 🌟
将操作分离出来,封装在一个“访问者”对象中,使得操作可以在不修改元素类的情况下添加到对象结构上。
模式结构(UML 类图)
+----------------------------+
| Visitor |
+----------------------------+
| + visitConcreteElementA() |
| + visitConcreteElementB() |
+----------------------------+
▲
+----------------+-----------------+
| |
+--------------------------+ +--------------------------+
| ConcreteVisitorA | | ConcreteVisitorB |
+--------------------------+ +--------------------------+
| + visitConcreteElementA()| | + visitConcreteElementB()|
+--------------------------+ +--------------------------+
+------------------+
| Element |
+------------------+
| + accept() |
+------------------+
▲
|
+----------------------+
| ConcreteElementA |
+----------------------+
| + accept() |
+----------------------+
示例场景
想象你有一个复杂的对象结构,比如各种不同类型的 Animal
(动物)类,你可能希望执行不同的操作,如发出声音。
但你不想在每个类中重复写操作代码。这时候,你就可以使用访问者模式。你可以创建一个“访问者”对象,它知道如何操作这些类,而不需要修改每个类的定义。
Java 实现
// 访问者接口
interface AnimalVisitor {
void visit(Dog dog);
void visit(Cat cat);
}
// 动物接口(元素)
interface Animal {
void accept(AnimalVisitor visitor);
}
// 具体元素
class Dog implements Animal {
public void accept(AnimalVisitor visitor) {
visitor.visit(this);
}
public void bark() {
System.out.println("Woof!");
}
}
class Cat implements Animal {
public void accept(AnimalVisitor visitor) {
visitor.visit(this);
}
public void meow() {
System.out.println("Meow!");
}
}
// 具体访问者
class AnimalSoundVisitor implements AnimalVisitor {
public void visit(Dog dog) {
dog.bark();
}
public void visit(Cat cat) {
cat.meow();
}
}
// 使用
public class Main {
public static void main(String[] args) {
Animal dog = new Dog();
Animal cat = new Cat();
AnimalVisitor soundVisitor = new AnimalSoundVisitor();
dog.accept(soundVisitor); // 输出:Woof!
cat.accept(soundVisitor); // 输出:Meow!
}
}
C++ 实现
#include <iostream>
using namespace std;
// 访问者接口
class AnimalVisitor {
public:
virtual void visit(class Dog&) = 0;
virtual void visit(class Cat&) = 0;
virtual ~AnimalVisitor() = default;
};
// 元素接口
class Animal {
public:
virtual void accept(AnimalVisitor& visitor) = 0;
virtual ~Animal() = default;
};
// 具体元素
class Dog : public Animal {
public:
void accept(AnimalVisitor& visitor) override {
visitor.visit(*this);
}
void bark() {
cout << "Woof!" << endl;
}
};
class Cat : public Animal {
public:
void accept(AnimalVisitor& visitor) override {
visitor.visit(*this);
}
void meow() {
cout << "Meow!" << endl;
}
};
// 具体访问者
class AnimalSoundVisitor : public AnimalVisitor {
public:
void visit(Dog& dog) override {
dog.bark();
}
void visit(Cat& cat) override {
cat.meow();
}
};
// 使用
int main() {
Dog dog;
Cat cat;
AnimalSoundVisitor soundVisitor;
dog.accept(soundVisitor); // 输出:Woof!
cat.accept(soundVisitor); // 输出:Meow!
return 0;
}
Python 实现
from abc import ABC, abstractmethod
# 访问者接口
class AnimalVisitor(ABC):
@abstractmethod
def visit(self, animal):
pass
# 元素接口
class Animal(ABC):
@abstractmethod
def accept(self, visitor):
pass
# 具体元素
class Dog(Animal):
def accept(self, visitor):
visitor.visit(self)
def bark(self):
print("Woof!")
class Cat(Animal):
def accept(self, visitor):
visitor.visit(self)
def meow(self):
print("Meow!")
# 具体访问者
class AnimalSoundVisitor(AnimalVisitor):
def visit(self, animal):
if isinstance(animal, Dog):
animal.bark()
elif isinstance(animal, Cat):
animal.meow()
# 使用
dog = Dog()
cat = Cat()
sound_visitor = AnimalSoundVisitor()
dog.accept(sound_visitor) # 输出:Woof!
cat.accept(sound_visitor) # 输出:Meow!
TypeScript 实现
interface Animal {
accept(visitor: AnimalVisitor): void;
}
interface AnimalVisitor {
visit(dog: Dog): void;
visit(cat: Cat): void;
}
class Dog implements Animal {
accept(visitor: AnimalVisitor): void {
visitor.visit(this);
}
bark() {
console.log("Woof!");
}
}
class Cat implements Animal {
accept(visitor: AnimalVisitor): void {
visitor.visit(this);
}
meow() {
console.log("Meow!");
}
}
class AnimalSoundVisitor implements AnimalVisitor {
visit(dog: Dog): void {
dog.bark();
}
visit(cat: Cat): void {
cat.meow();
}
}
// 使用
const dog = new Dog();
const cat = new Cat();
const soundVisitor = new AnimalSoundVisitor();
dog.accept(soundVisitor); // 输出:Woof!
cat.accept(soundVisitor); // 输出:Meow!
小结
特性 | 内容 |
---|---|
模式类型 | 行为型 |
适用场景 |
|
优点 |
|
缺点 |
|
访问者模式是处理复杂对象结构时非常有用的模式,它使得你可以把操作逻辑和数据结构分离开,遵循了“开放/封闭原则”,非常适合需要增加新操作而不修改已有元素类的场景。