访问者模式(Visitor Pattern)
模式定义
封装某些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。
UML类图
- 抽象访问者(Vistor) 声明一个或多个访问抽象节点类型的抽象方法(参数为抽象节点类型),依赖抽象节点类型。
- 具体访问者(ConcreteElement) 实现抽象访问者角色中所有声明的接口。
- 抽象元素(Element) 声明节点被访问者访问的方法,依赖与访问者。
- 具体元素(ConcreteElement) 实现抽象元素所规定的接受操作。
- 对象结构(ObjectStructure) 节点的容器,可以包含多个不同类或接口的容器。
代码结构
public static class VisitorApp
{
public static void Run()
{
ObjectStructure o = new ObjectStructure();
o.Attach(new ConcreteElementA());
o.Attach(new ConcreteElementB());
// Create visitor objects
ConcreteVisitor1 v1 = new ConcreteVisitor1();
ConcreteVisitor2 v2 = new ConcreteVisitor2();
// Structure accepting visitors
o.Accept(v1);
o.Accept(v2);
}
}
abstract class Visitor
{
public abstract void VisitConcreteElementA(ConcreteElementA concreteElementA);
public abstract void VisitConcreteElementB(ConcreteElementB concreteElementB);
}
class ConcreteVisitor1 : Visitor
{
public override void VisitConcreteElementA(ConcreteElementA concreteElementA)
{
Console.WriteLine("{0} visited by {1}", concreteElementA.GetType().Name, this.GetType().Name);
}
public override void VisitConcreteElementB(ConcreteElementB concreteElementB)
{
Console.WriteLine("{0} visited by {1}", concreteElementB.GetType().Name, this.GetType().Name);
}
}
class ConcreteVisitor2 : Visitor
{
public override void VisitConcreteElementA(ConcreteElementA concreteElementA)
{
Console.WriteLine("{0} visited by {1}", concreteElementA.GetType().Name, this.GetType().Name);
}
public override void VisitConcreteElementB(ConcreteElementB concreteElementB)
{
Console.WriteLine("{0} visited by {1}", concreteElementB.GetType().Name, this.GetType().Name);
}
}
abstract class Element
{
public abstract void Accept(Visitor visitor);
}
class ConcreteElementA : Element
{
public override void Accept(Visitor visitor)
{
visitor.VisitConcreteElementA(this);
}
}
class ConcreteElementB : Element
{
public override void Accept(Visitor visitor)
{
visitor.VisitConcreteElementB(this);
}
}
class ObjectStructure
{
private List<Element> _elements = new List<Element>();
public void Attach(Element element)
{
_elements.Add(element);
}
public void Detach(Element element)
{
_elements.Remove(element);
}
public void Accept(Visitor visitor)
{
foreach (Element element in _elements)
{
element.Accept(visitor);
}
}
}
情景案例
这种模式在.Net 框架中没必要按部就班的这么麻烦的用了。.Net 框架中ForEach(Action<T> action)
遍历集合执行每个元素执行委托。
public static class VisitorRealWorldApp
{
public static void Run()
{
List<string> lst = new List<string>() { "Item1", "Item2", "Item3" };
lst.ForEach(i => Console.WriteLine("方法一 " + i.ToString()));
lst.ForEach(i => Console.WriteLine("方法二 " + i.ToString()));
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)