设计模式之访问者模式详解(定义、优缺点、应用场景、实例类图)
在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。
一、访问者模式的介绍
意图
旨在将数据结构与在该数据结构上执行的操作分离,从而使得添加新的操作变得更容易,而无需修改数据结构本身。
主要解决的问题
解决在稳定数据结构和易变操作之间的耦合问题,使得操作可以独立于数据结构变化。
使用场景
当需要对一个对象结构中的对象执行多种不同的且不相关的操作时,尤其是这些操作需要避免"污染"对象类本身。
实现方式
定义访问者接口:声明一系列访问方法,一个访问方法对应数据结构中的一个元素类。
创建具体访问者:实现访问者接口,为每个访问方法提供具体实现。
定义元素接口:声明一个接受访问者的方法。
创建具体元素:实现元素接口,每个具体元素类对应数据结构中的一个具体对象。
关键代码
访问者接口:包含访问不同元素的方法。
具体访问者:实现了访问者接口,包含对每个元素类的访问逻辑。
元素接口:包含一个接受访问者的方法。
具体元素:实现了元素接口,提供给访问者访问的入口。
结构
包含的几个主要角色
访问者(Visitor):
定义了访问元素的接口。
具体访问者(Concrete Visitor):
实现访问者接口,提供对每个具体元素类的访问和相应操作。
元素(Element):
定义了一个接受访问者的方法。
具体元素(Concrete Element):
实现元素接口,提供一个accept方法,允许访问者访问并操作。
对象结构(Object Structure)(可选):
定义了如何组装具体元素,如一个组合类。
客户端(Client)(可选):
使用访问者模式对对象结构进行操作。
应用实例
做客场景:访问者(如您)访问朋友家,朋友作为元素提供信息,访问者根据信息做出判断。
二、访问者模式的优缺点
优点
单一职责原则:访问者模式符合单一职责原则,每个类只负责一项职责。
扩展性:容易为数据结构添加新的操作。
灵活性:访问者可以独立于数据结构变化。
缺点
违反迪米特原则:元素需要向访问者公开其内部信息。
元素类难以变更:元素类需要维持与访问者的兼容。
依赖具体类:访问者模式依赖于具体类而不是接口,违反了依赖倒置原则。
三、访问者模式的使用建议
当对象结构稳定,但需要在其上定义多种新操作时,考虑使用访问者模式。
当需要避免操作"污染"对象类时,使用访问者模式封装操作。
访问者模式可以用于功能统一,如报表生成、用户界面显示、拦截器和过滤器等。
四、访问者模式的实现
我们将创建一个定义接受操作的 ComputerPart 接口。Keyboard、Mouse、Monitor 和 Computer 是实现了 ComputerPart 接口的实体类。我们将定义另一个接口 ComputerPartVisitor,它定义了访问者类的操作。Computer 使用实体访问者来执行相应的动作。
VisitorPatternDemo,我们的演示类使用 Computer、ComputerPartVisitor 类来演示访问者模式的用法。

步骤 1:定义一个表示元素的接口。
ComputerPart.java
publicinterfaceComputerPart{
publicvoidaccept(ComputerPartVisitorcomputerPartVisitor);
}步骤 2:创建扩展了上述类的实体类。
Keyboard.java
publicclassKeyboardimplementsComputerPart{
@Override
publicvoidaccept(ComputerPartVisitorcomputerPartVisitor){
computerPartVisitor.visit(this);
}
}Monitor.java
publicclassMonitorimplementsComputerPart{
@Override
publicvoidaccept(ComputerPartVisitorcomputerPartVisitor){
computerPartVisitor.visit(this);
}
}Mouse.java
publicclassMouseimplementsComputerPart{
@Override
publicvoidaccept(ComputerPartVisitorcomputerPartVisitor){
computerPartVisitor.visit(this);
}
}Computer.java
publicclassComputerimplementsComputerPart{
ComputerPart[]parts;
publicComputer(){
parts=newComputerPart[]{newMouse(),newKeyboard(),newMonitor()};
}
@Override
publicvoidaccept(ComputerPartVisitorcomputerPartVisitor){
for(inti=0;i<parts.length;i++){
parts[i].accept(computerPartVisitor);
}
computerPartVisitor.visit(this);
}
}步骤 3:定义一个表示访问者的接口。
ComputerPartVisitor.java
publicinterfaceComputerPartVisitor{
publicvoidvisit(Computercomputer);
publicvoidvisit(Mousemouse);
publicvoidvisit(Keyboardkeyboard);
publicvoidvisit(Monitormonitor);
}步骤 4:创建实现了上述类的实体访问者。
ComputerPartDisplayVisitor.java
publicclassComputerPartDisplayVisitorimplementsComputerPartVisitor{
@Override
publicvoidvisit(Computercomputer){
System.out.println("DisplayingComputer.");
}
@Override
publicvoidvisit(Mousemouse){
System.out.println("DisplayingMouse.");
}
@Override
publicvoidvisit(Keyboardkeyboard){
System.out.println("DisplayingKeyboard.");
}
@Override
publicvoidvisit(Monitormonitor){
System.out.println("DisplayingMonitor.");
}
}步骤 5:使用 ComputerPartDisplayVisitor 来显示 Computer 的组成部分。
VisitorPatternDemo.java
publicclassVisitorPatternDemo{
publicstaticvoidmain(String[]args){
ComputerPartcomputer=newComputer();
computer.accept(newComputerPartDisplayVisitor());
}
}步骤 6:执行程序,输出结果:
DisplayingMouse.
DisplayingKeyboard.
DisplayingMonitor.
DisplayingComputer.
以上就是php小编整理的全部内容,希望对您有所帮助,更多相关资料请查看php教程栏目。
-
什么是VoIP?它是如何工作的?VoIP的工作原理 时间:2025-11-07 -
MPEG-4是什么格式 MPEG-4和MP4的区别 时间:2025-11-07 -
什么是OAuth OAuth2.0认证原理和流程 OAuth2.0授权机制 时间:2025-11-07 -
什么是IMAP协议 IMAP协议和POP3协议的区别 时间:2025-11-07 -
什么是最大传输单元(MTU) 最大传输单元设置多少合适 时间:2025-11-07 -
什么是云存储 云存储的优势和应用场景 云存储有哪些类型 云存储如何工作 时间:2025-11-07
今日更新
-
2025年稳定币信任度排行:USDT、USDC与DAI三大首选币种解析
阅读:18
-
愚人节是什么梗 揭秘整蛊狂欢背后的网络热梗真相
阅读:18
-
2025全球顶级DEX推荐:Uniswap PancakeSwap SushiSwap性能解析
阅读:18
-
2025年机构重仓数字货币投资指南:BTC、ETH、LINK领衔榜单
阅读:18
-
什么节奏是什么梗?揭秘网络热词背后的爆笑真相,3秒get流行密码!
阅读:18
-
天刀手游玄素鸿蒙外观上线-天气动作蜃镜裂世震撼登场
阅读:18
-
忘川风华录名士墨子技能详细-墨子怎么培养
阅读:18
-
2025三大潜力黑马币:SUI ENA ARB爆发式增长预测
阅读:18
-
王者荣耀最新英雄调整发布-花木兰增强元辅助全面升级
阅读:18
-
明日方舟:终末地帝江号概况-干员进驻舱室参考
阅读:18










