首页 > 其他分享 >Go 设计模式中访问者模式

Go 设计模式中访问者模式

时间:2023-09-03 21:34:03浏览次数:39  
标签:Visitor 元素 ConcreteElementA Accept ConcreteElementB Go 设计模式 访问者


鱼弦:全栈领域创作新星创作者 、51CTO(Top红人+专家博主) 、github开源爱好者(go-zero源码二次开发、游戏后端架构 https://github.com/Peakchen)

Go 设计模式中访问者模式_访问者

在Go设计模式中,访问者模式(Visitor Pattern)是一种行为型模式,用于将算法与数据结构分离,使得算法可以独立地操作数据结构的不同元素,同时遵循开闭原则。

原理详细解释:
访问者模式的核心思想是将数据结构与对数据的操作分离。它通过定义一个访问者(Visitor)接口,该接口包含了对数据结构中每个元素的操作方法。数据结构中的每个元素都要实现一个接受访问者的方法,将自身传递给访问者,并在访问者中调用相应的操作方法。

在访问者模式中,通常有以下几个角色:

  1. Visitor(访问者接口):定义了对数据结构中每个元素的操作方法。
  2. ConcreteVisitor(具体访问者类):实现了Visitor接口,具体实现了对数据结构中每个元素的操作方法。
  3. Element(元素接口):定义了接受访问者的方法。
  4. ConcreteElement(具体元素类):实现了Element接口,实现了接受访问者的方法,并将自身传递给访问者。
  5. ObjectStructure(对象结构):包含了一个或多个元素,提供了遍历元素的方法。

访问者模式的优点在于可以在不修改数据结构的情况下,增加新的操作。但缺点是增加新的元素类型会较为困难,需要修改所有的访问者类。

底层结构图:
以下是访问者模式的底层结构图:

+-------------------------+
    |       Visitor           |
    +-------------------------+
    | + VisitConcreteElementA |
    | + VisitConcreteElementB |
    +-------------------------+
              /|\
               |
               |
    +-------------------------+
    |    ConcreteVisitorA     |
    +-------------------------+
    | + VisitConcreteElementA |
    +-------------------------+
              /|\
               |
               |
    +-------------------------+
    |    ConcreteVisitorB     |
    +-------------------------+
    | + VisitConcreteElementB |
    +-------------------------+
               /|\
                |
                |
    +-----------------------+
    |      Element          |
    +-----------------------+
    | + Accept(Visitor)     |
    +-----------------------+
              /|\
               |
               |
    +-----------------------+
    |  ConcreteElementA     |
    +-----------------------+
    | + Accept(Visitor)     |
    +-----------------------+
              /|\
               |
               |
    +-----------------------+
    |  ConcreteElementB     |
    +-----------------------+
    | + Accept(Visitor)     |
    +-----------------------+
               |
               |
    +-----------------------+
    |   ObjectStructure     |
    +-----------------------+
    | + Attach(Element)     |
    | + Detach(Element)     |
    | + Accept(Visitor)     |
    +-----------------------+

使用场景解释:
访问者模式适用于以下情况:

  1. 当一个数据结构中的元素类型很少发生变化,但需要定义多个不同的操作时,可以使用访问者模式。它将每个操作都封装在一个独立的访问者类中,使得操作可以独立地变化和扩展。
  2. 当一个数据结构中的元素类型较多,但每个元素都需要进行不同的操作时,可以使用访问者模式。通过访问者模式,可以避免在数据结构中添加大量的条件语句,使得代码更加清晰和可维护。
  3. 当对数据结构的元素进行操作时,不希望修改元素的类定义,可以使用访问者模式。访问者模式将操作封装在访问者类中,使得操作可以独立于元素类进行扩展。

代码示例实现:
下面是一个简单的访问者模式的示例,假设有以下是一个使用Golang实现的访问者模式示例:

package main

import "fmt"

// Visitor 访问者接口
type Visitor interface {
	VisitConcreteElementA(element ConcreteElementA)
	VisitConcreteElementB(element ConcreteElementB)
}

// ConcreteVisitorA 具体访问者A
type ConcreteVisitorA struct{}

// VisitConcreteElementA 具体访问者A对ConcreteElementA的操作
func (v ConcreteVisitorA) VisitConcreteElementA(element ConcreteElementA) {
	fmt.Println("ConcreteVisitorA访问ConcreteElementA")
}

// VisitConcreteElementB 具体访问者A对ConcreteElementB的操作
func (v ConcreteVisitorA) VisitConcreteElementB(element ConcreteElementB) {
	fmt.Println("ConcreteVisitorA访问ConcreteElementB")
}

// ConcreteVisitorB 具体访问者B
type ConcreteVisitorB struct{}

// VisitConcreteElementA 具体访问者B对ConcreteElementA的操作
func (v ConcreteVisitorB) VisitConcreteElementA(element ConcreteElementA) {
	fmt.Println("ConcreteVisitorB访问ConcreteElementA")
}

// VisitConcreteElementB 具体访问者B对ConcreteElementB的操作
func (v ConcreteVisitorB) VisitConcreteElementB(element ConcreteElementB) {
	fmt.Println("ConcreteVisitorB访问ConcreteElementB")
}

// Element 元素接口
type Element interface {
	Accept(visitor Visitor)
}

// ConcreteElementA 具体元素A
type ConcreteElementA struct{}

// Accept 接受访问者的操作
func (e ConcreteElementA) Accept(visitor Visitor) {
	visitor.VisitConcreteElementA(e)
}

// ConcreteElementB 具体元素B
type ConcreteElementB struct{}

// Accept 接受访问者的操作
func (e ConcreteElementB) Accept(visitor Visitor) {
	visitor.VisitConcreteElementB(e)
}

// ObjectStructure 对象结构
type ObjectStructure struct {
	elements []Element
}

// Attach 添加元素
func (o *ObjectStructure) Attach(element Element) {
	o.elements = append(o.elements, element)
}

// Detach 移除元素
func (o *ObjectStructure) Detach(element Element) {
	for i, e := range o.elements {
		if e == element {
			o.elements = append(o.elements[:i], o.elements[i+1:]...)
			break
		}
	}
}

// Accept 接受访问者的操作
func (o ObjectStructure) Accept(visitor Visitor) {
	for _, element := range o.elements {
		element.Accept(visitor)
	}
}

func main() {
	// 创建具体元素
	elementA := ConcreteElementA{}
	elementB := ConcreteElementB{}

	// 创建具体访问者
	visitorA := ConcreteVisitorA{}
	visitorB := ConcreteVisitorB{}

	// 创建对象结构
	objectStructure := ObjectStructure{}
	objectStructure.Attach(elementA)
	objectStructure.Attach(elementB)

	// 对象结构接受具体访问者A的操作
	objectStructure.Accept(visitorA)

	// 对象结构接受具体访问者B的操作
	objectStructure.Accept(visitorB)
}

在上面的示例中,我们定义了Visitor接口和两个具体的Visitor类:ConcreteVisitorA和ConcreteVisitorB。然后我们定义了Element接口和两个具体的Element类:ConcreteElementA和ConcreteElementB。最后,我们定义了ObjectStructure类来管理元素,并实现了Attach、Detach和Accept方法。在main函数中,我们创建了具体的元素和访问者,并将元素添加到对象结构中。然后,我们分别让对象结构接受具体访问者A和具体访问者B的操作。

文献材料链接:
以下是一些关于访问者模式的参考文献链接:

  1. Design Patterns: Elements of Reusable Object-Oriented Software (Gang of Four book)
  1. SourceMaking - Visitor Pattern
  1. Refactoring Guru - Visitor Pattern

当前都有哪些产品在使用:

访问者模式是一种常用的设计模式,可以在许多不同的领域和产品中找到应用。以下是一些使用访问者模式的常见产品和框架:

  1. 编译器和解析器:访问者模式常用于编译器和解析器的实现中,用于遍历抽象语法树(Abstract Syntax Tree,AST)并执行相应的操作。
  2. 文档处理工具:访问者模式可以用于处理文档结构,例如解析和操作HTML、XML或Markdown文档。
  3. 图形处理库:访问者模式可以用于图形处理库,用于遍历图形对象的层次结构并执行相应的操作,如绘制、变换或计算。
  4. 数据库访问框架:访问者模式可以用于数据库访问框架,用于遍历数据库表或查询结果,并执行相应的操作,如映射到对象模型或执行业务逻辑。
  5. 游戏引擎:访问者模式可以用于游戏引擎中的场景管理、碰撞检测和物理引擎等方面,用于遍历游戏对象并执行相应的操作。

标签:Visitor,元素,ConcreteElementA,Accept,ConcreteElementB,Go,设计模式,访问者
From: https://blog.51cto.com/chenfenglove/7343342

相关文章

  • MongoDB 会丢数据吗? 在次补刀MongoDB 双机热备
    以后会争取每天一段感悟,不讨论对错,幼儿园的孩子才每件事论对错最强大的,这个词不一定是个好词,最强大的往往是最虚弱的,那些天天和你谈格局,谈奉献,谈爱,强大的人,很可能内心和垃圾堆里面的碎玻璃一样,闪闪发光。如何和这样的人交往呢,一定要把自己碎的更厉害,发出耀眼的光,此刻他就不和你谈格......
  • Google C++编程规范(Google C++ Style Guide)
    参考链接:Google代码规范C++总结Google开源项目风格指南——中文版GoogleC++StyleGuide是一份不错的C++编码指南,我制作了一张比较全面的说明图,可以在短时间内快速掌握规范的重点内容。不过规范毕竟是人定的,记得活学活用。看图前别忘了阅读下面两条重要建议:保持一致也......
  • 2023-09-03:用go编写。给你一个 n 个节点的无向无根树,节点编号从 0 到 n - 1 给你整数
    2023-09-03:用go语言编写。给你一个n个节点的无向无根树,节点编号从0到n-1给你整数n和一个长度为n-1的二维整数数组edges,其中edges[i]=[ai,bi]表示树中节点ai和bi之间有一条边。再给你一个长度为n的数组coins,其中coins[i]可能为0也可能为1,1表示节......
  • 2023-09-03:用go编写。给你一个 n 个节点的无向无根树,节点编号从 0 到 n - 1 给你整数
    2023-09-03:用go语言编写。给你一个n个节点的无向无根树,节点编号从0到n-1给你整数n和一个长度为n-1的二维整数数组edges,其中edges[i]=[ai,bi]表示树中节点ai和bi之间有一条边。再给你一个长度为n的数组coins,其中coins[i]可能为0也可能为1,1......
  • 设计模式:通俗易懂版
    ......
  • 两个例子理解js设计模式中的【适配器模式】
    适配器模式的精髓:如果现有的接口已经能够正常工作,那我们就永远不会用上适配器模式。适配器模式是一种“亡羊补牢”的模式,没有人会在程序的设计之初就使用它。因为没有人可以完全预料到未来的事情,也许现在好好工作的接口,未来的某天却不再适用于新系统,那么我们可以用适配器模式把旧......
  • 基于Hugo的github个人博客的搭建
    一、前期准备以windows系统为例1.下载Git(https://git-scm.com/downloads)2.下载Hugo(https://github.com/gohugoio/hugo/releases)按照自己电脑下。3.设置环境变量:打开环境变量可以看到在系统变量有一个变量名为PATH的变量,直接点击然后编辑,把自己的git和hugo的位置添加进去。注意不是......
  • golang base64解码
    解码过程1.使用标准库的base64.StdEncoding.DecodeString 最开始是印象标准库有一个base64.StdEncoding.DecodeString方法可以解码,就直接使用了这个方法packagemainimport("encoding/base64""fmt")funcmain(){encrypt:="Cf1WA2nBMo3H9G2UPhlLBBVB......
  • mongodb副本集(仲裁模式)修改各节点ip(update方式)
    环境:OS:Centos7mongodb:5.0当前的ip  变更后的ip192.168.1.105192.168.1.108PRIMARY192.168.1.106192.168.1.109SECONDARY192.168.1.107192.168.1.110ARBITER 1.查看当前的集群登录一个节点......
  • GO语言工程实践课后作业
    项目背景该项目是一个基于Gin框架开发的消息板应用,提供发布话题和回复功能。GinGin是一个基于Go语言的轻量级Web框架,它提供了快速构建高性能Web应用程序的工具和功能。以下是Gin框架的一些特点和使用方法:特点:快速:Gin是一个非常快速的框架,因为它使用了Radix树路由和高......