设计模式学习笔记:访问者模式(含设计模式概述)

自用学习笔记

设计模式

【狂神说Java】通俗易懂的23种设计模式教学(停更)_哔哩哔哩_bilibili

【2021版】马士兵重讲23种设计模式,居然能这么通俗易懂_哔哩哔哩_bilibili

23种设计模式

  • 设计模式概述

概念:设计模式(Design Pattern)是前辈们对代码开发经验的总结,是解决特定问题的一系列套路。它不是语法规定,而是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案。

  1. 主要针对面向对象软件设计
  2. 95年,GoF四人帮合伙出了一本书,收录23设计模式,又称GoF设计模式

学习一个设计模式要了解的:1)模式名称;2)要解决的问题;3)解决问题的方案;4)效果(该模式的优缺点)

23种模式:

创建型模式:描述如何创建一个对象,st对象的创建和使用分离

结构型模式:

行为型模式:描述类之间如何相互协作 完成某种行为

  • 访问者模式

【2021版】马士兵重讲23种设计模式,居然能这么通俗易懂_哔哩哔哩_bilibili

在结构不变的情况下,动态改变对于内部元素的动作

例子:编译器中,做语法分析时对AST的分析,就要用到visitor模式。(例如babel的AST 就是用的visitor模式的设计思路)

例子:

Computer类由cpu、内存、主板组成,他们都是抽象类ComputerPart

现在模拟攒机:

现在需求:个人用户(学生或上班族打不同折扣)来攒机可以打少量折扣、企业用户来攒机可以打很多折扣

解决办法:

法一:

在CPU里面写一个accept方法 接受一个visitor(用户),然后里面用各种if判断来的用户是啥 然后给xxx折扣

但这种写法不好:

  1. 把各种if语句都要写到CPU memory board里
  2. 如果要新增一种用户折扣 又要在每个computerpart里面改,改的东西太多了

法二:即上面代码实现的功能,比如cpu的accept方法就调用visitor.visitCPU()方法,要求每个来访者都实现visitCPU visitmemory等方法。

重点:

1)Computer(某个大结构,如树)的子结构接待来访者

2)具体的接待策略由来访者自己定义、实现

看代码:

这样 就实现了不同来访者访问相同子结构,实现的效果不一样

看下面结构图:

重点:

  1. 子结构需要有接受visitor的accept方法
  2. Accept方法中调用visitor的访问自己的方法
  3. 不同的visitor要各自实现访问不同子结构的方法

【比如上面图的例子 AST有不同类型节点 访问者有不同类型(如typecheck、codegenerate等)】

Visitor模式的好处/特点:

  1. computer类不用再变了,除非你要加新的子结构【但visitor模式一般适用于访问结构固定的东西,如果这个东西的结构一直在变的,就不适合使用访问者模式】

适用于被处理的数据元素相对稳定,而访问方式多种多样的数据结构。

  1. 本质是把子结构中的各种if语句抽象到visitor接口里面。本质是把处理方法从数据结构中分离出来,并可以根据需要增加新的处理方法,且不用修改原来的程序代码与数据结构

Visitor模式的应用:(GoF例子)

编译器中对AST做不同操作(如类型检查:比如检查+号操作符左右元素是不是都是数字类型,检查赋值语句两边元素的类型是否一致等;如生成中间代码;如AST beautifier)

即我们需要访问AST(结构固定),且有各种不同的访问的需求(visitor不同)

传统方法:

每个节点都定义visitor的不同动作 很麻烦

Visitor模式方法:

只给节点定义accept 只调用visitor自己的visit方法

然后每种visitor具体要做什么,在自己visitor里面定义,就不写在节点里面了

【所以说babel中的访问节点就是用的visitor模式】

babel-handbook/plugin-handbook.md at master · jamiebuilds/babel-handbook · GitHub

例如在babel plugin的编写中,我们可以自己定义visitor,定义我们访问不同节点时的动作。比如当时我有个插桩的需求,在所有函数定义的开头和结尾加入统计函数执行时间的代码。即我们就可以在定义当我们访问到functiondeclaration节点时,在其子节点插入一个functioncall节点。

而不是在functiondeclaration中改。。。

在现实生活中,有些集合对象存在多种不同的元素,且每种元素也存在多种不同的访问者和处理方式。例如,公园中存在多个景点,也存在多个游客,不同的游客对同一个景点的评价可能不同;医院医生开的处方单中包含多种药元素,査看它的划价员和药房工作人员对它的处理方式也不同,划价员根据处方单上面的药品名和数量进行划价,药房工作人员根据处方单的内容进行抓药。

这样的例子还有很多,例如,电影或电视剧中的人物角色,不同的观众对他们的评价也不同;还有顾客在商场购物时放在“购物车”中的商品,顾客主要关心所选商品的性价比,而收银员关心的是商品的价格和数量。

这些被处理的数据元素相对稳定访问方式多种多样的数据结构,如果用“访问者模式”来处理比较方便。访问者模式能把处理方法从数据结构中分离出来,并可以根据需要增加新的处理方法,且不用修改原来的程序代码与数据结构,这提高了程序的扩展性和灵活性。

但实际上,Visitor模式的使用场景比较窄,基本就应用编译器这个专业领域了。

代码例子:

https://github.com/TeraniteAK/ProgrammingPractice/tree/main/JavaVisitorDesignPattern

【总结】

1)模式名称:访问者模式

2)要解决的问题:被处理的数据元素相对稳定,而访问方式多种多样的数据结构。即要求用多种访问方式访问一个结构相对固定的数据结构。

3)解决问题的方案:将访问逻辑从数据结构本身抽离出来,把访问逻辑放在visitor中。

4)效果(该模式的优缺点)

  1. 适用于被处理的数据元素相对稳定,而访问方式多种多样的数据结构。换言之,如果数据结构需要不定期变换,就不适合使用访问者模式
  2. 把数据结构的处理方式和数据结构本身分离开来,方便增加新的对数据结构的访问/处理方式。
  3. 实际应用中基本只用在compiler中对AST的访问。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值