全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

如何使用Golang实现访问者模式_在不修改对象结构前提下增加功能

访问者模式的核心思想是将操作与数据结构分离,Golang通过接口、方法集和类型组合实现:定义Element接口含Accept方法,各具体元素实现该方法并调用visitor对应VisitXXX;Visitor接口声明各类Visit方法,新增功能只需实现该接口,无需修改原有结构。

访问者模式的核心思想是把“操作”从“数据结构”中分离出来,让新增功能无需改动原有结构代码。Golang 没有传统面向对象的继承和虚函数,但可以通过接口、方法集和类型组合优雅实现该模式。

定义元素接口与具体元素

先定义一个 Element 接口,要求所有可被访问的对象都实现 Accept(visitor Visitor) 方法:

type Element interface {
    Accept(Visitor) // 接收访问者
}

再为每种具体数据结构(如文件、目录、链接)实现该接口。关键点是:每个 Accept 方法内部调用 visitor.VisitXXX(this),把自身作为参数传给访问者对应的方法:

  • 文件类型示例:
type File struct {
    Name string
    Size int
}

func (f *File) Accept(v Visitor) {
    v.VisitFile(f)
}
  • 目录类型示例:
type Directory struct {
    Name     string
    Children []Element
}

func (d *Directory) Accept(v Visitor) {
    v.VisitDirectory(d)
}

定义访问者接口与具体访问者

定义 Visitor 接口,声明对每种元素类型的处理方法:

type Visitor interface {
    VisitFile(*File)
    VisitDirectory(*Directory)
}

新增功能只需实现这个接口,例如统计总大小的访问者:

type SizeCalculator struct {
    Total int
}

func (s *SizeCalculator) VisitFile(f *File) {
    s.Total += f.Size
}

func (s *SizeCalculator) VisitDirectory(d *Directory) {
    // 目录本身不占空间,但需递归访问子项
    for _, child := range d.Children {
        child.Accept(s) // 递归分发
    }
}

再比如打印路径的访问者:

type PathPrinter struct {
    Prefix string
}

func (p *PathPrinter) VisitFile(f *File) {
    fmt.Println(p.Prefix + "/" + f.Name)
}

func (p *PathPrinter) VisitDirectory(d *Directory) {
    fmt.Println(p.Prefix + "/" + d.Name)
    for _, child := range d.Children {
        child.Accept(&PathPrinter{Prefix: p.Prefix + "/" + d.Name})
    }
}

使用访问者遍历对象结构

客户端只需创建元素树,然后传入任意访问者实例即可执行新逻辑,完全不修改 FileDirectory 的定义:

root := &Directory{
    Name: "root",
    Children: []Element{
        &File{Name: "readme.txt", Size: 1024},
        &Directory{
            Name: "src",
            Children: []Element{
                &File{Name: "main.go", Size: 2048},
            },
        },
    },
}

// 统计大小
calc := &SizeCalculator{}
root.Accept(calc)
fmt.Println("Total size:", calc.Total) // 输出 3072

// 打印路径
printer := &PathPrinter{Prefix: ""}
root.Accept(printer)

注意事项与优化建议

Golang 中实现访问者模式需注意几点:

  • 接口方法名需明确区分类型:如 VisitFileVisitDirectory,避免类型擦除后无法分发
  • 访问者通常需要状态:用结构体实现,而非函数闭包,便于复用和测试
  • 递归访问由访问者自己控制:比如 VisitDirectory 内手动调用 child.Accept(v),保持灵活性
  • 若元素类型较多,可借助代码生成工具(如 stringer 思路)自动生成 Accept 方法,减少模板代码

不复杂但容易忽略。


# go  # golang  # 工具  # ai  # 面向对象  # Directory  # 结构体  # 递归  # 数据结构  # 继承  # 虚函数  # 接口  # 闭包  # 对象  # this  # 只需  # 新增功能  # 遍历  # 可以通过  # 较多  # 几点  # 而非  # 自动生成 


相关文章: 高端企业智能建站程序:SEO优化与响应式模板定制开发  宝塔建站助手安装配置与建站模板使用全流程解析  哪家制作企业网站好,开办像阿里巴巴那样的网络公司和网站要怎么做?  北京建设网站制作公司,北京古代建筑博物馆预约官网?  制作旅游网站html,怎样注册旅游网站?  建站主机与虚拟主机有何区别?如何选择最优方案?  网站专业制作公司有哪些,做一个公司网站要多少钱?  如何用5美元大硬盘VPS安全高效搭建个人网站?  建站主机无法访问?如何排查域名与服务器问题  建站主机选虚拟主机还是云服务器更好?  子杰智能建站系统|零代码开发与AI生成SEO优化指南  怎么将XML数据可视化 D3.js加载XML  公司网站制作费用多少,为公司建立一个网站需要哪些费用?  小建面朝正北,A点实际方位是否存在偏差?  定制建站模板如何实现SEO优化与智能系统配置?18字教程  盐城做公司网站,江苏电子版退休证办理流程?  制作网站的软件免费下载,免费制作app哪个平台好?  建站之星如何优化SEO以实现高效排名?  黑客如何利用漏洞与弱口令入侵网站服务器?  头像制作网站在线制作软件,dw网页背景图像怎么设置?  建站之星免费版是否永久可用?  北京网站制作网页,网站升级改版需要多久?  网站企业制作流程,用什么语言做企业网站比较好?  邀请函制作网站有哪些,有没有做年会邀请函的网站啊?在线制作,模板很多的那种?  建站之星安装模板失败:服务器环境不兼容?  如何在自有机房高效搭建专业网站?  广州顶尖建站服务:企业官网建设与SEO优化一体化方案  郑州企业网站制作公司,郑州招聘网站有哪些?  魔毅自助建站系统:模板定制与SEO优化一键生成指南  高性能网站服务器配置指南:安全稳定与高效建站核心方案  C++用Dijkstra(迪杰斯特拉)算法求最短路径  ,sp开头的版面叫什么?  微信小程序 input输入框控件详解及实例(多种示例)  我的世界制作壁纸网站下载,手机怎么换我的世界壁纸?  如何配置WinSCP新建站点的密钥验证步骤?  ,网页ppt怎么弄成自己的ppt?  如何通过西部建站助手安装IIS服务器?  ,巨量百应是干嘛的?  如何通过VPS搭建网站快速盈利?  在线ppt制作网站有哪些,请推荐几个好的课件下载的网站?  视频网站app制作软件,有什么好的视频聊天网站或者软件?  魔方云NAT建站如何实现端口转发?  音响网站制作视频教程,隆霸音响官方网站?  新网站制作渠道有哪些,跪求一个无线渠道比较强的小说网站,我要发表小说?  北京网页设计制作网站有哪些,继续教育自动播放怎么设置?  建站之星如何通过成品分离优化网站效率?  南京网站制作费用,南京远驱官方网站?  如何在阿里云虚拟机上搭建网站?步骤解析与避坑指南  建站之星如何修改网站生成路径?  如何通过IIS搭建网站并配置访问权限? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。