访问者模式通过双重分发解耦数据结构与操作。其核心在于:1. 定义 element 接口,包含 accept 方法;2. 定义 visitor 接口,包含多个 visit 方法;3. 具体 element 实现 accept 并调用对应 visit 方法。在 golang 中,虽无继承机制,但通过接口实现双重分发,即运行时根据 element 和 visitor 的实际类型决定调用的具体方法。示例中 book 和 dvd 实现 accept,并由 pricevisitor 统一处理打印价格。该模式要求清晰设计接口,新增 element 需同步更新所有 visitor 实现,适合结构稳定、需统一处理的场景,且可通过抽象工厂或依赖注入提升扩展性。

访问者模式的核心在于解耦数据结构和作用于其上的操作。在 Golang 中,虽然没有继承机制,但通过接口(interface)可以巧妙地实现“双重分发”,从而模拟访问者模式的行为。

这篇文章就来聊聊如何用 Golang 实现访问者模式,重点是基于接口的双重分发技巧。

访问者模式允许你定义一组操作,这些操作可以作用于某个对象结构中的不同元素,而无需修改这些元素本身的类。这种模式特别适合需要对复杂对象结构进行统一处理的场景。
立即学习“go语言免费学习笔记(深入)”;
核心概念有两个:

Accept(v Visitor))。VisitXxx 方法,对应不同的 Element 类型。关键点在于:访问者调用元素的 Accept 方法,而元素又反过来调用访问者的 Visit 方法,这就是所谓的“双重分发”。
Golang 没有类和继承,但可以通过接口和函数组合实现类似效果。下面是具体步骤:
举个简单例子,假设我们有两个元素类型:Book 和 DVD,我们要实现打印价格的操作。
type Visitor interface {
VisitBook(book *Book)
VisitDVD(dvd *DVD)
}
type Element interface {
Accept(visitor Visitor)
}具体元素:
type Book struct {
Price float64
}
func (b *Book) Accept(visitor Visitor) {
visitor.VisitBook(b)
}
type DVD struct {
Price float64
}
func (d *DVD) Accept(visitor Visitor) {
visitor.VisitDVD(d)
}然后定义一个打印价格的访问者:
type PriceVisitor struct{}
func (v *PriceVisitor) VisitBook(book *Book) {
fmt.Println("Book price:", book.Price)
}
func (v *PriceVisitor) VisitDVD(dvd *DVD) {
fmt.Println("DVD price:", dvd.Price)
}这样就可以统一处理了:
elements := []Element{
&Book{Price: 59.9},
&DVD{Price: 39.9},
}
visitor := &PriceVisitor{}
for _, e := range elements {
e.Accept(visitor)
}双重分派的意思是:方法调用不是只看调用者的静态类型,而是根据运行时两个对象的实际类型决定调用哪个方法。
在上面的例子中:
e.Accept(visitor) 的时候,Go 根据 e 的实际类型调用对应结构体的 Accept 方法。visitor.VisitXXX(e) 这一步,根据 visitor 的类型和 e 的类型,最终调用了正确的 Visit 方法。虽然 Go 是静态语言,也没有重载,但通过这种方式实现了类似动态双分发的效果。
如果你发现 Visitor 接口变得越来越大,可能说明职责划分有问题,可以考虑拆分访问者功能。
基本上就这些。访问者模式在 Golang 中虽然不如 Java 那样自然,但通过接口和双重分发机制,依然可以优雅地实现。关键是理解 Accept 和 Visit 的调用关系,以及 Visitor 接口的设计方式。
以上就是如何用Golang实现访问者模式 基于接口的双重分发技巧的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号