一、访问者模式
概述
在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作
主要解决:
解决在稳定数据结构和易变操作之间的耦合问题,使得操作可以独立于数据结构变化
何时使用:
- 当需要对数据结构中的元素进行多种操作,并且这些操作之间存在一定的关联或依赖关系时,可以使用访问者模式。访问者模式可以通过在访问者中保存中间结果或状态,实现多个操作之间的数据共享和协作
优缺点
优点:
- 单一职责原则:访问者模式符合单一职责原则,每个类只负责一项职责
- 扩展性:容易为数据结构添加新的操作
- 灵活性:访问者可以独立于数据结构变化
缺点:
- 违反迪米特原则:元素需要向访问者公开其内部信息
- 元素类难以变更:元素类需要维持与访问者的兼容
- 依赖具体类:访问者模式依赖于具体类而不是接口,违反了依赖倒置原则
注意事项
- 访问者模式可以用于功能统一,如报表生成、用户界面显示、拦截器和过滤器等
1. 各个角色介绍
1.1 访问者(Visitor)
- 定义了访问元素的接口
1.2 具体访问者(Concrete Visitor)
- 实现访问者接口,提供对每个具体元素类的访问和相应操作
1.3 元素(Element)
- 定义了一个接受访问者的方法
1.4 具体元素(Concrete Element)
- 实现元素接口,提供一个
accept
方法,允许访问者访问并操作
1.5 对象结构(Object Structure)(可选)
- 定义了如何组装具体元素,如一个组合类
2. UML图
我们将创建一个定义接受操作的 ComputerPart 接口。Keyboard、Mouse、Monitor 和 Computer 是实现了 ComputerPart 接口的实体类。我们将定义另一个接口 ComputerPartVisitor,它定义了访问者类的操作。Computer 使用实体访问者来执行相应的动作
3. 具体例子和代码
角色分配
-
ComputerPart:电脑零件
-
Computer:电脑
-
Keyboard:键盘
-
Monitor:显示器
-
Mouse:鼠标
-
-
ComputerPartVisitor:电脑零件访问者
- ComputerPartDisplayVisitor:电脑零件展示访问者
3.1 访问者接口及其实现类
- ComputerPartVisitor
package com.vinjcent.prototype.visitor;
/**
* @author vinjcent
* @description 电脑零件访问者(访问者角色)
* @since 2024/6/5 19:43
*/
public interface ComputerPartVisitor {
/**
* 访问电脑
*
* @param computer 电脑
*/
void visit(Computer computer);
/**
* 访问鼠标
*
* @param mouse 鼠标
*/
void visit(Mouse mouse);
/**
* 访问键盘
*
* @param keyboard 键盘
*/
void visit(Keyboard keyboard);
/**
* 访问显示器
*
* @param monitor 显示器
*/
void visit(Monitor monitor);
}
- ComputerPartDisplayVisitor
package com.vinjcent.prototype.visitor;
/**
* @author vinjcent
* @description 电脑零件展示访问者
* @since 2024/6/5 20:00
*/
public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
@Override
public void visit(Computer computer) {
System.out.println("Displaying Computer.");
}
@Override
public void visit(Mouse mouse) {
System.out.println("Displaying Mouse.");
}
@Override
public void visit(Keyboard keyboard) {
System.out.println("Displaying Keyboard.");
}
@Override
public void visit(Monitor monitor) {
System.out.println("Displaying Monitor.");
}
}
3.3 测试主函数
package com.vinjcent.prototype.visitor;
/**
* @author vinjcent
* @description 访问者模式
* @since 2024/6/5 20:07
*/
public class Main {
public static void main(String[] args) {
ComputerPart computer = new Computer();
computer.accept(new ComputerPartDisplayVisitor());
}
}
- 测试结果
4. 使用场景
- 当需要对一个对象结构中的对象执行多种不同的且不相关的操作时,尤其是这些操作需要避免"污染"对象类本身