# 访问者模式
# 概念
访问者模式是一种行为设计模式,允许在不修改已有代码的情况下,动态地添加新的操作到对象结构中。它将数据结构与操作解耦,使得可以独立地定义作用于复杂对象结构的操作。
# 作用
1.解耦数据结构与操作:将作用于对象结构的操作与对象结构本身分离,使两者可以独立变化。
2.符合单一职责原则:将相关操作集中到访问者类中,避免对象类承担过多职责。
3.符合开闭原则:新增操作时无需修改对象类代码,只需添加新的访问者类即可。
4.支持动态扩展:可在运行时通过更换访问者实例,灵活切换对象结构的操作逻辑。
# 场景
1.对象结构包含多个类对象,且需对这些对象实施依赖其具体类型的操作。
2.需对对象结构执行大量不相关操作,且希望避免操作“污染”对象类。
3.对象结构类型稳定但操作频繁变化,需经常新增操作而少修改对象结构。
4.需集中管理作用于对象结构的所有操作,便于维护和扩展。
# 举例
以下为访问者模式的Java代码示例:
// 访问者接口
interface ComputerPartVisitor {
void visit(Mouse mouse);
void visit(Keyboard keyboard);
void visit(Display display);
void visit(Computer computer);
}
// 具体访问者 - 清洁访问者
class CleanVisitor implements ComputerPartVisitor {
@Override
public void visit(Mouse mouse) { System.out.println("清洁鼠标"); }
@Override
public void visit(Keyboard keyboard) { System.out.println("清洁键盘"); }
@Override
public void visit(Display display) { System.out.println("清洁显示器"); }
@Override
public void visit(Computer computer) { System.out.println("清洁电脑"); }
}
// 具体访问者 - 升级访问者
class UpgradeVisitor implements ComputerPartVisitor {
@Override
public void visit(Mouse mouse) { System.out.println("升级鼠标驱动"); }
@Override
public void visit(Keyboard keyboard) { System.out.println("升级键盘驱动"); }
@Override
public void visit(Display display) { System.out.println("升级显示器驱动"); }
@Override
public void visit(Computer computer) { System.out.println("升级电脑系统"); }
}
// 元素接口
interface ComputerPart {
void accept(ComputerPartVisitor visitor);
}
// 具体元素 - 鼠标
class Mouse implements ComputerPart {
@Override
public void accept(ComputerPartVisitor visitor) { visitor.visit(this); }
}
// 具体元素 - 键盘
class Keyboard implements ComputerPart {
@Override
public void accept(ComputerPartVisitor visitor) { visitor.visit(this); }
}
// 具体元素 - 显示器
class Monitor implements ComputerPart {
@Override
public void accept(ComputerPartVisitor visitor) { visitor.visit(this); }
}
// 具体元素 - 电脑(包含其他元素的容器)
class Computer implements ComputerPart {
private List<ComputerPart> parts = new ArrayList<>();
public Computer() {
parts.add(new Mouse());
parts.add(new Keyboard());
parts.add(new Monitor());
}
@Override
public void accept(ComputerPartVisitor visitor) {
for (ComputerPart part : parts) part.accept(visitor);
visitor.visit(this);
}
}
// 测试类
public class VisitorPatternDemo {
public static void main(String[] args) {
Computer computer = new Computer();
computer.accept(new CleanVisitor()); // 输出清洁操作
computer.accept(new UpgradeVisitor()); // 输出升级操作
}
}
# 反例
不使用访问者模式时,通常会在对象类中直接添加操作方法:
// 鼠标类(含清洁和升级方法)
class Mouse {
public void clean() { System.out.println("清洁鼠标"); }
public void upgrade() { System.out.println("升级鼠标驱动"); }
}
// 键盘类(含清洁和升级方法)
class Keyboard {
public void clean() { System.out.println("清洁键盘"); }
public void upgrade() { System.out.println("升级键盘驱动"); }
}
// 显示器类(含清洁和升级方法)
class Monitor {
public void clean() { System.out.println("清洁显示器"); }
public void upgrade() { System.out.println("升级显示器驱动"); }
}
// 电脑类(管理子元素并调用其方法)
class Computer {
private List<Object> parts = new ArrayList<>();
public Computer() {
parts.add(new Mouse());
parts.add(new Keyboard());
parts.add(new Monitor());
}
public void clean() {
System.out.println("清洁电脑");
for (Object part : parts) {
if (part instanceof Mouse) ((Mouse)part).clean();
else if (part instanceof Keyboard) ((Keyboard)part).clean();
else if (part instanceof Monitor) ((Monitor)part).clean();
}
}
public void upgrade() {
System.out.println("升级电脑系统");
for (Object part : parts) {
if (part instanceof Mouse) ((Mouse)part).upgrade();
else if (part instanceof Keyboard) ((Keyboard)part).upgrade();
else if (part instanceof Monitor) ((Monitor)part).upgrade();
}
}
}
// 测试类
public class NoVisitorPatternDemo {
public static void main(String[] args) {
new Computer().clean(); // 输出清洁操作
new Computer().upgrade(); // 输出升级操作
}
}
此方式会导致对象类承担过多操作方法,新增操作时需修改所有对象类,违反开闭原则,且代码冗余度高。
# 原理
访问者模式通过“双分派”机制实现操作与对象的解耦:对象结构中的元素通过accept()
方法接收访问者,并调用访问者的visit()
方法,将自身类型作为参数传递。访问者根据元素类型执行对应操作,从而将操作逻辑集中到访问者类中,避免对象类因新增操作而频繁修改。
# 缺点
1.元素与访问者强耦合:元素类接口变化时,所有访问者类需同步修改。
2.破坏封装性:元素类需暴露内部细节(如通过accept()
方法传递this
引用)。
3.适用场景受限:对象结构元素类型频繁变化时,维护访问者成本高。
4.学习成本较高:双分派机制和接口设计对开发者要求较高。
总结
访问者模式通过解耦对象结构与操作,实现了操作的动态扩展,符合开闭原则和单一职责原则,适用于对象结构稳定但操作频繁变化的场景。其核心优势在于集中管理操作逻辑,但需权衡元素接口稳定性与维护成本,避免在元素类型多变的场景下过度使用。

微信公众号

QQ交流群
如若发现错误,诚心感谢反馈。
愿你倾心相念,愿你学有所成。
愿你朝华相顾,愿你前程似锦。