简介
访问者模式(Visitor Pattern)是一种行为型模式。它封装一个访问者类,把各元素类的操作集合起来,目的是将数据结构与数据操作分离。在不改变原有元素类数据结构的前提下,改变了元素类的执行算法。
当某些较为稳定的东西(数据结构或算法),不想直接被改变但又想扩展功能,这时候适合用访问者模式。访问者模式的使用频率并不是很高,大多数情况下,你并不需要使用访问者模式,但是当你一旦需要使用它时,那你就是需要使用它了。
访问者模式有以下几个角色:
- 结构对象(ObjectStructure):结构对象角色,这是访问者模式的基础角色,包含多个类或者接口.
- 抽象元素(Element):定义一个接受访问操作accept(),以一个访问者Visitor作为参数。
- 具体元素(ConcreteElement):实现抽象节点的accept()方法和处理操作,调用Vistor的访问方法实现具体功能。
- 抽象访问者(Visitor):定义一个抽象接口,声明一个或多个访问操作,使得所有具体访问者都必须实现。
- 具体访问者(ConcreteVisitor):具体访问者角色,实现Visitor声明的接口。
作用
- 在数据基础类里面有一个方法接受访问者,将自身引用传入访问者,从而把不变的固定起来,把变化的开放出去。
- 通过隔离类中变化的东西,固定不变的东西,符合单一职责原则,同时具备较好的扩展性和灵活性。
实现步骤
- 先创建基本元素抽象类Element,确定accept()抽象方法。
- 分别创建几个具体的元素类,实现抽象元素的accept方法。
- 在创建Visitor抽象接口,定义visit方法,调用具体元素。
- 创建1个或多个Visitor类,继承抽象接口,客户将以此去访问具体元素。
- 再创建对象结构类,这是核心入口类,负责组合各种元素,以及传递访问者Visitor。
- 客户调用时先创建对象结构类,再指定访问者类,通过访问这类调用具体元素类
UML

Java代码
结构对象
| |
| public class ObjectStructure { |
| |
| |
| private String name = "Computer Structure"; |
| private List<Element> elements = new ArrayList<Element>(); |
| |
| |
| public ObjectStructure() { |
| addElement(new ConcreteElementA()); |
| addElement(new ConcreteElementB()); |
| } |
| |
| public void addElement(Element element) { |
| elements.add(element); |
| } |
| |
| |
| public void accept(Visitor visitor) { |
| System.out |
| .println("ObjectStructure::accept() [visitor.class = " + visitor.getClass().getSimpleName() + " visitor.name = " |
| + visitor.getName() + "]"); |
| for (Element element : elements) { |
| element.accept(visitor); |
| } |
| } |
| |
| public String getName() { |
| return this.name; |
| } |
| |
| } |
抽象访问者类
| |
| public interface Visitor { |
| public void visit(ConcreteElementA concreteElementA); |
| |
| public void visit(ConcreteElementB concreteElementB); |
| |
| public String getName(); |
| } |
具体访问者
| |
| public class ConcreteVisitorA implements Visitor { |
| |
| |
| private String name = "Google Visitor"; |
| |
| @Override |
| public void visit(ConcreteElementA concreteElementA) { |
| System.out.println( |
| "ConcreteVisitorA::visit() [Element.class = " + concreteElementA.getClass().getSimpleName() |
| + " Element.name = " |
| + concreteElementA.getName() + "]"); |
| concreteElementA.operate(); |
| } |
| |
| @Override |
| public void visit(ConcreteElementB concreteElementB) { |
| System.out.println("ConcreteVisitorA::visit() [Element.class = " + concreteElementB.getClass().getSimpleName() |
| + " Element.name = " |
| + concreteElementB.getName() + "]"); |
| concreteElementB.operate(); |
| } |
| |
| public String getName() { |
| return this.name; |
| } |
| } |
| |
| public class ConcreteVisitorB implements Visitor { |
| |
| |
| private String name = "Apple Visitor"; |
| |
| @Override |
| public void visit(ConcreteElementA concreteElementA) { |
| System.out.println( |
| "ConcreteVisitorB::visit() [Element.class = " + concreteElementA.getClass().getSimpleName() |
| + " Element.name = " |
| + concreteElementA.getName() + "]"); |
| concreteElementA.operate(); |
| } |
| |
| @Override |
| public void visit(ConcreteElementB concreteElementB) { |
| System.out.println( |
| "ConcreteVisitorB::visit() [Element.class = " + concreteElementB.getClass().getSimpleName() |
| + " Element.name = " |
| + concreteElementB.getName() + "]"); |
| concreteElementB.operate(); |
| } |
| |
| public String getName() { |
| return this.name; |
| |
| } |
| } |
抽象元素类
| |
| abstract class Element { |
| public abstract void accept(Visitor visitor); |
| } |
具体元素实现类
| |
| public class ConcreteElementA extends Element { |
| |
| private String name = "Monitor Element"; |
| |
| @Override |
| public void accept(Visitor visitor) { |
| System.out |
| .println( |
| "ConcreteElementA::accept() [visitor.class = " + visitor.getClass().getSimpleName() + " visitor.name = " |
| + visitor.getName() + "]"); |
| visitor.visit(this); |
| } |
| |
| public void operate() { |
| System.out.println("ConcreteElementA::operate() [" + this.getName() + "]"); |
| } |
| |
| public String getName() { |
| return this.name; |
| } |
| } |
| |
| public class ConcreteElementB extends Element { |
| private String name = "Keyboard Element"; |
| |
| @Override |
| public void accept(Visitor visitor) { |
| System.out.println( |
| "ConcreteElementB::accept() [visitor.class = " + visitor.getClass().getSimpleName() + " visitor.name = " |
| + visitor.getName() + "]"); |
| visitor.visit(this); |
| } |
| |
| public void operate() { |
| System.out.println("ConcreteElementB::operate() [" + this.getName() + "]"); |
| } |
| |
| public String getName() { |
| return this.name; |
| } |
| } |
测试调用
| |
| |
| |
| |
| |
| ObjectStructure structure = new ObjectStructure(); |
| |
| structure.accept(new ConcreteVisitorA()); |
| |
| System.out.println("===="); |
| |
| structure.accept(new ConcreteVisitorB()); |
Go代码
结构对象
| |
| type ObjectStructure struct { |
| name string |
| elements []Element |
| } |
| |
| func (o *ObjectStructure) AddElement(e Element) { |
| o.elements = append(o.elements, e) |
| } |
| |
| |
| func (o *ObjectStructure) Accept(v Visitor) { |
| fmt.Println( |
| "ObjectStructure::Accept() [Visitor.name = " + |
| v.GetName() + "]") |
| |
| |
| for i := 0; i < len(o.elements); i++ { |
| o.elements[i].Accept(v) |
| } |
| |
| |
| |
| |
| } |
| |
| func (o *ObjectStructure) GetName() string { |
| o.name = "Computer Structure" |
| return o.name |
| } |
| |
| |
| func (o *ObjectStructure) Init() { |
| |
| fmt.Println("ObjectStructure::Init() ", o.GetName()) |
| |
| o.elements = make([]Element, 0, 100) |
| |
| |
| o.AddElement(&ConcreteElementA{}) |
| o.AddElement(&ConcreteElementB{}) |
| } |
抽象访问者类
| |
| type Visitor interface { |
| VisitA(e *ConcreteElementA) |
| VisitB(e *ConcreteElementB) |
| GetName() string |
| } |
具体访问者
| |
| type ConcreteVisitorA struct { |
| name string |
| } |
| |
| func (v *ConcreteVisitorA) GetName() string { |
| v.name = "Google Visitor(struct=ConcreteVisitorA)" |
| return v.name |
| } |
| |
| func (v *ConcreteVisitorA) VisitA(e *ConcreteElementA) { |
| fmt.Println( |
| "ConcreteVisitorA::VisitA() [Element.name = " + e.GetName() + "]") |
| e.Operate() |
| } |
| |
| func (v *ConcreteVisitorA) VisitB(e *ConcreteElementB) { |
| fmt.Println( |
| "ConcreteVisitorA::VisitB() [Element.name = " + e.GetName() + "]") |
| e.Operate() |
| } |
| |
| type ConcreteVisitorB struct { |
| name string |
| } |
| |
| func (v *ConcreteVisitorB) GetName() string { |
| v.name = "Apple Visitor(struct=ConcreteVisitorB)" |
| return v.name |
| } |
| |
| func (v *ConcreteVisitorB) VisitB(e *ConcreteElementB) { |
| fmt.Println( |
| "ConcreteVisitorB::VisitB() [Element.name = " + e.GetName() + "]") |
| e.Operate() |
| } |
| |
| func (v *ConcreteVisitorB) VisitA(e *ConcreteElementA) { |
| fmt.Println( |
| "ConcreteVisitorB::VisitA() [Element.name = " + e.GetName() + "]") |
| e.Operate() |
| } |
抽象元素类
| |
| |
| type Element interface { |
| Accept(v Visitor) |
| Operate() |
| GetName() string |
| } |
具体元素实现类
| |
| type ConcreteElementA struct { |
| name string |
| } |
| |
| func (c *ConcreteElementA) GetName() string { |
| c.name = `Monitor Element(struct=ConcreteElementA)` |
| return c.name |
| } |
| |
| func (e *ConcreteElementA) Accept(v Visitor) { |
| fmt.Println( |
| "ConcreteElementA::Accept() [Visitor.name = " + v.GetName() + "]") |
| v.VisitA(e) |
| } |
| |
| func (e *ConcreteElementA) Operate() { |
| fmt.Println("ConcreteElementA::Operate() [" + e.GetName() + "]") |
| } |
| |
| type ConcreteElementB struct { |
| name string |
| } |
| |
| func (c *ConcreteElementB) GetName() string { |
| c.name = "Keyboard Element(struct=ConcreteElementB)" |
| return c.name |
| } |
| |
| func (e *ConcreteElementB) Accept(v Visitor) { |
| fmt.Println( |
| "ConcreteElementB::Accept() [Visitor.name = " + v.GetName() + "]") |
| v.VisitB(e) |
| } |
| |
| func (e *ConcreteElementB) Operate() { |
| fmt.Println("ConcreteElementB::Operate() [" + e.GetName() + "]") |
| } |
测试调用
| func main() { |
| fmt.Println("test start:") |
| |
| |
| |
| |
| |
| |
| structure := src.ObjectStructure{} |
| structure.Init() |
| |
| structure.Accept(&src.ConcreteVisitorA{}) |
| |
| fmt.Println("====") |
| |
| structure.Accept(&src.ConcreteVisitorB{}) |
| } |
更多语言版本
不同语言设计模式源码:https://github.com/microwind/design-pattern
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现