【设计模式】行为型-访问者模式

张开发
2026/6/11 2:19:44 15 分钟阅读
【设计模式】行为型-访问者模式
文章目录前言一、概念二、核心结构三、Java 代码实现文件系统文件文件夹1. 抽象元素FileSystemElement2. 具体元素文件 File3. 具体元素文件夹 Folder4. 抽象访问者 Visitor5. 具体访问者1打印功能6. 具体访问者2计算总大小7. 客户端四、双分派核心机制五、优缺点优点缺点六、应用场景七、访问者 VS 迭代器 VS 组合八、总结前言在开发中我们经常遇到稳定的数据结构 多变的操作逻辑场景比如一个树形结构文件、订单、商品需要新增打印、压缩、审计、报表等不同功能。如果每次加功能都去修改元素类会严重违背开闭原则。访问者模式就是专门解决稳定结构、多变操作的行为型设计模式让你不修改元素就能无限扩展新功能。一、概念访问者模式Visitor Pattern是一种行为型设计模式核心思想封装作用于某种数据结构如List、Set、Map、组合树中各元素的操作在不改变元素类的前提下定义作用于这些元素的新操作。简单理解数据结构元素稳定不变功能访问者可以无限扩展把操作从元素类中抽离出来交给访问者双分派元素接受访问访问者处理元素一句话总结结构不动功能扩展数据归你操作归我。二、核心结构Visitor抽象访问者为每类元素声明一个访问方法。ConcreteVisitor具体访问者实现具体操作逻辑打印、报表、压缩等。Element抽象元素提供accept(Visitor)方法接受访问。ConcreteElement具体元素实现accept允许访问者访问自己。ObjectStructure对象结构持有元素集合可遍历让访问者访问。三、Java 代码实现文件系统文件文件夹结构文件夹组合 文件叶子功能打印、提取大小两个访问者1. 抽象元素FileSystemElementpublicinterfaceFileSystemElement{voidaccept(Visitorvisitor);}2. 具体元素文件 FilepublicclassFileimplementsFileSystemElement{privateStringname;privateintsize;publicFile(Stringname,intsize){this.namename;this.sizesize;}Overridepublicvoidaccept(Visitorvisitor){visitor.visit(this);// 双分派核心}// getter 给访问者使用publicStringgetName(){returnname;}publicintgetSize(){returnsize;}}3. 具体元素文件夹 Folderimportjava.util.ArrayList;importjava.util.List;publicclassFolderimplementsFileSystemElement{privateStringname;privateListFileSystemElementchildrennewArrayList();publicFolder(Stringname){this.namename;}publicvoidadd(FileSystemElemente){children.add(e);}Overridepublicvoidaccept(Visitorvisitor){visitor.visit(this);// 递归让子元素接受访问for(FileSystemElemente:children)e.accept(visitor);}publicStringgetName(){returnname;}publicListFileSystemElementgetChildren(){returnchildren;}}4. 抽象访问者 VisitorpublicinterfaceVisitor{voidvisit(Filefile);voidvisit(Folderfolder);}5. 具体访问者1打印功能publicclassPrintVisitorimplementsVisitor{Overridepublicvoidvisit(Filefile){System.out.println(文件file.getName() 大小file.getSize());}Overridepublicvoidvisit(Folderfolder){System.out.println(文件夹folder.getName());}}6. 具体访问者2计算总大小publicclassSizeVisitorimplementsVisitor{privateinttotalSize0;Overridepublicvoidvisit(Filefile){totalSizefile.getSize();}Overridepublicvoidvisit(Folderfolder){// 文件夹本身不计大小只遍历子元素}publicintgetTotalSize(){returntotalSize;}}7. 客户端publicclassClient{publicstaticvoidmain(String[]args){FolderrootnewFolder(root);Filef1newFile(a.txt,10);Filef2newFile(b.jpg,20);FoldersubnewFolder(sub);Filef3newFile(c.md,30);sub.add(f3);root.add(f1);root.add(f2);root.add(sub);// 打印System.out.println( 打印访问者 );VisitorprintnewPrintVisitor();root.accept(print);// 统计大小System.out.println(\n 大小访问者 );SizeVisitorsizeVisitornewSizeVisitor();root.accept(sizeVisitor);System.out.println(总大小sizeVisitor.getTotalSize());}}输出 打印访问者 文件夹root 文件a.txt 大小10 文件b.jpg 大小20 文件夹sub 文件c.md 大小30 大小访问者 总大小60四、双分派核心机制第一次分派element.accept(visitor)第二次分派visitor.visit(this)结果执行的是【具体元素 具体访问者】的组合方法→ 这就是访问者能精准匹配类型的原因。五、优缺点优点优秀的扩展性加新功能只需加访问者不改元素职责单一元素存数据访问者做操作集中式操作可一次性对整个结构做统一处理适合组合结构 多种算法缺点元素结构不能变增删元素类要改所有Visitor破坏封装Visitor需要访问元素内部数据复杂度高理解成本高六、应用场景组合结构文件树、订单树、AST需频繁新增操作但结构稳定报表、打印、审计、校验、压缩、序列化编译器、IDE插件、代码检查经典应用MyBatis Mapper 解析Spring Event 访问式监听Java NIO 文件访问IDEA 代码检查/重构七、访问者 VS 迭代器 VS 组合组合树形结构迭代器遍历元素访问者对元素做不同操作遍历处理一体八、总结访问者模式 稳定结构 无限扩展操作核心双分派、数据与操作分离最适合组合结构 多算法/多报表是设计模式中最难但最强大的模式之一

更多文章