设计模式第22讲——访问者模式(Visitor)

news2024/11/26 8:27:53

目录

一、什么是访问者模式

二、角色组成

三、优缺点

四、 应用场景

4.1 生活场景

4.2 Java场景

五、代码实现

5.0 UML类图

 5.1 抽象访问者——Visitor

5.2 具体访问者——Tourist

5.3 抽象元素——Spot

5.4 具体元素——View、Relic

5.5 对象结构——SpotCollection

5.6 testVisitor

六、总结 


一、什么是访问者模式

访问者模式是一种行为型设计模式,它可以用于在不修改已有对象结构的情况下,定义新的操作方式。简单地说就是在不改变数据结构的前提下,通过在数据结构中加入一个新的角色——访问者,来达到执行不同操作的目的。

二、角色组成

  • 抽象访问者(Visitor):定义了对自身数据结构中各个元素的操作,为每个具体元素类对应一个访问操作,该操作中的参数标识了被访问的具体元素。
  • 具体访问者(Concrete Visitor):实现了访问者接口中定义的具体操作,确定访问者访问一个元素时该做什么。
  • 抽象元素(Element):定义了接受访问者的接口,通常是一个接口或抽象类,其中定义了一个接受访问者的方法,被访问者对象作为方法的参数。
  • 具体元素(Concrete Element):实现了抽象元素接口,它是数据结构中的具体的元素,用于接收具体的访问者并执行相应的操作。每个具体元素都有自己的业务逻辑,并在接收访问者时将具体的操作委托给访问者进行处理。
  • 对象结构(Object Structure):是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现。

三、优缺点

优点:

  • 扩展性好:能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
  • 复用性好:可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。
  • 灵活性好:访问者模式将数据结构与作用于结构上的操作解耦,使得操作集合可相对自由地演化而不影响系统的数据结构。
  • 符合单一职责原则。访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一。

缺点:

  • 违反开闭原则:在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”。
  • 违反迪米特法则:在访问者模式中,具体元素类需要暴露接受访问者的方法给访问者使用,这样破坏了具体元素类对于访问者的封装性,增加了元素类与具体访问者之间的耦合性。
  • 破坏封装性:访问者模式中具体元素对访问者公布细节,这破坏了对象的封装性。

四、 应用场景

4.1 生活场景

  • 蔬菜摊位:在一个农贸市场的蔬菜摊位上,摊主可能提供不同的服务,如称重、清洗、切割等。每个服务可以被视为一个访问者,而蔬菜则是元素,根据不同的服务访问者进行相应的操作。
  • 医院就诊:在医院就诊时,医生、护士和药师可以视为不同的访问者,而病人则是元素。不同的访问者根据其职责和需要,对病人进行不同的操作和处理,如诊断、治疗、开药等。
  • 旅游参观:游客可以参观不同的地方,如参观文物、欣赏风景等。游客可以看作访问者,而景点本身则是元素,根据游客的选择展示不同的参观操作。

4.2 Java场景

  • XML解析器:许多Java XML解析器,如DOM和SAX解析器,使用访问者模式来处理XML文档。XML的节点可以被视为元素,而访问者则可以是处理XML节点的具体操作,如提取数据、修改节点等。
  • 数据库访问:一些Java数据库访问框架,如Hibernate和MyBatis,使用访问者模式来处理数据库操作。数据库表和字段可以被视为元素,而访问者则可以是查询、更新或删除操作,通过访问者模式来执行这些操作。
  • 文件系统操作:Java的文件和目录操作中,使用了访问者模式。Java提供了FileVisitor接口和SimpleFileVisitor类,可以通过自定义的访问者类来遍历文件系统,并执行不同的操作,如复制文件、删除文件等。

五、代码实现

下面以“旅游参观”为例,解释一下访问者模式。游客挑选不同的景点来参观,如参观文物、欣赏风景等。那么游客可以看作访问者,而景点本身则是元素,根据游客的选择展示不同的参观操作。

  • 抽象访问者:Visitor
  • 具体访问者:Tourist
  • 抽象元素:Spot
  • 具体元素:Relic、View
  • 对象结构:SpotCollection

5.0 UML类图

 

 5.1 抽象访问者——Visitor

/**
 * @author Created by njy on 2023/7/4
 * 1.抽象访问者(Visitor):参观者
 * 定义:定义了对自身数据结构中各个元素的操作,为每个具体元素类对应一个访问操作,该操作中的参数标识了被访问的具体元素。
 */
public interface Visitor {
    void visit(Relic relic);
    void visit(View scenery);
}

5.2 具体访问者——Tourist

/**
 * @author Created by njy on 2023/7/4
 * 2.具体访问者(Concrete Visitor):游客
 * 定义:实现了访问者接口中定义的具体操作,确定访问者访问一个元素时该做什么。
 */
public class Tourist implements Visitor{
    @Override
    public void visit(Relic relic) {
        System.out.println("游客正在参观文物...");
        relic.display();
    }

    @Override
    public void visit(View scenery) {
        System.out.println("游客正在欣赏自然风景...");
        scenery.display();
    }
}

5.3 抽象元素——Spot

/**
 * @author Created by njy on 2023/7/4
 * 3.抽象元素(Element):景点
 * 定义:定义了接受访问者的接口,通常是一个接口或抽象类,其中定义了一个接受访问者的方法,被访问者对象作为方法的参数。
 */
public interface Spot {
    void accept(Visitor visitor);
}

5.4 具体元素——View、Relic

/**
 * @author Created by njy on 2023/7/4
 * 4.具体元素(Concrete Element):风景
 * 定义:实现了抽象元素接口,它是数据结构中的具体的元素,用于接收具体的访问者并执行相应的操作。
 * 每个具体元素都有自己的业务逻辑,并在接收访问者时将具体的操作委托给访问者进行处理。
 */
public class View implements Spot{
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this); // 将自身传递给访问者
    }
    // 具体自然风景的业务逻辑
    public void display() {
        System.out.println("这是一处壮丽的自然风景。");
    }
}
/**
 * @author Created by njy on 2023/7/4
 * 4.具体元素(Concrete Element):文物
 * 定义:实现了抽象元素接口,它是数据结构中的具体的元素,用于接收具体的访问者并执行相应的操作。
 * 每个具体元素都有自己的业务逻辑,并在接收访问者时将具体的操作委托给访问者进行处理。
 */
public class Relic implements Spot{
    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this); // 将自身传递给访问者
    }
    // 具体文物的业务逻辑
    public void display() {
        System.out.println("这是一件珍贵的文物。");
    }
}

5.5 对象结构——SpotCollection

/**
 * @author Created by njy on 2023/7/4
 * 5.对象结构(Object Structure)
 * 定义:包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现。
 */
public class SpotCollection {
    private List<Spot> spots = new ArrayList<>();

    //添加元素
    public void addSpot(Spot spot) {
        spots.add(spot);
    }

    public void accept(Visitor visitor) {
        for (Spot spot : spots) {
            spot.accept(visitor);
        }
    }
}

5.6 testVisitor

/**
 * @author Created by njy on 2023/7/5
 * 访问者模式测试类
 */
@SpringBootTest
public class TestVisitor {

    @Test
    void testVisitor(){
        //创建对象结构
        SpotCollection spotCollection = new SpotCollection();
        //添加元素
        spotCollection.addSpot(new Relic());
        spotCollection.addSpot(new View());

        Tourist tourist = new Tourist();
        //景点接受游客的访问
        spotCollection.accept(tourist);
    }
}

六、总结 

访问者模式主要用于将操作与数据结构分离,增加新的操作变得简单,但增加新的元素类可能会导致修改访问者接口和所有的具体访问者类。

以下情况,可以考虑使用访问者模式:

  • 当对象结构中的元素类(Element)和操作类(Operation)的种类固定或者很少改变,但是需要经常新增或者修改操作时。
  • 当需要对一个对象结构中的元素进行多种不同且无关的操作时。
  • 当需要对不同类型的元素对象进行某种共同的处理逻辑时。
  • 当对象结构中的元素类(Element)和操作类(Operation)的种类很多,并且相互之间的组合和嵌套可能会产生大量的代码重复时。
  • 当需要在不修改元素对象的类结构的前提下,给元素对象新增一些操作时。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/720652.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大厂面试打起12万分小心?3轮技术面过,你也可能挂在HR手上!

很多朋友在面试大厂时存在一个误区&#xff0c;认为面试你的那个是最初给你打电话的HR&#xff0c;其实不然&#xff0c;更大可能是业务部门相关的 HRBP导致你面试失败。 1、什么是HRBP? 为了解释清楚这个问题&#xff0c;先说 HRBP 是什么。HRBP全称为 Human Resource Busin…

java对象clone

Object提供了colne方法给我们定义的类&#xff0c;用来进行对象克隆&#xff0c;但是这个clone方法是protected的&#xff0c;所以需要在我们需要使用clone的类中重写Object的clone方法&#xff0c;并且需要实现Cloneable接口&#xff0c;Cloneable接口是一个标记接口&#xff…

「JVS低代码开发平台2.1.8版本」-首页功能介绍

JVS是面向软件开发团队可以快速实现应用的基础开发脚手架&#xff0c;主要定位于企业信息化通用底座&#xff0c;采用微服务分布式框架&#xff0c;提供丰富的基础功能&#xff0c;集成众多业务引擎&#xff0c;它灵活性强&#xff0c;界面化配置对开发者友好&#xff0c;底层容…

【Java】Netty中ByteBuf学习笔记

文章目录 1) ByteBuf创建与自动扩容2&#xff09;直接内存 vs 堆内存3&#xff09;池化 vs 非池化4&#xff09;组成5&#xff09;写入6&#xff09;扩容7&#xff09;读取8&#xff09;retain & release9&#xff09;slice10&#xff09;duplicate11&#xff09;copy12&am…

给LLM装上知识:从LangChain+LLM的本地知识库问答到LLM与知识图谱的结合

第一部分 基于LangChain ChatGLM-6B的本地知识库问答的应用实现 1.1 什么是LangChain&#xff1a;连接本地知识库与LLM的桥梁 作为一个 LLM 应用框架&#xff0c;LangChain 支持调用多种不同模型&#xff0c;提供相对统一、便捷的操作接口&#xff0c;让模型即插即用&#x…

java并发编程 6:java内存模型与volatile(重点)

目录 硬件内存模型Java 内存模型主内存工作内存内存交互的八个原子操作JMM作用 可见性退不出的循环volatile解决同步模式之 Balking 有序性指令重排解决指令重排 volatile 原理volatile如何保证可见性volatile如何保证有序性volatile 不能解决指令交错double-checked locking 问…

2023/7/5总结

JS BOM 是浏览器对象模型 window对象是一个全局对象&#xff0c;也是JavaScript的顶级对象 所以通过var定义在全局作用域中的变量、函数都会变成window对象的属性和方法 定时器-延时函数 setTimeout(回调函数&#xff0c;等待的毫秒数) 延时函数只会执行一次 清除延时函…

Java基础---String的长度限制

目录 典型回答 常量池限制 运行期限制 典型回答 String有长度限制&#xff0c;编译期和运行期不一样编译期需要用 CONSTANT_Utf8_info 结构用于表示字符串常量的值&#xff0c;而这个结构是有长度限制&#xff0c;他的限制是65535运行期&#xff0c;String的length参数是Int…

Jenkins 配置用户角色和权限

1、配置条件&#xff1a; 1&#xff09;已安装Jenkins&#xff0c;当前案例使用版本&#xff1a;2.319.3 2&#xff09;已成功进入Jenkins&#xff0c;并新建用户&#xff1a;dev_java 2、安装插件【系统管理-插件管理-搜索-可选插件】&#xff1a;Role-based Authoriz…

JavaScript 进阶 - 第4天

JavaScript 进阶 - 第4天笔记 文章目录 JavaScript 进阶 - 第4天笔记1 深浅拷贝1.1 浅拷贝1.2 深拷贝&#xff08;面试&#xff09;1.2.1 递归实现深拷贝1.2.2 js库lodash里面cloneDeep内部实现了深拷贝1.2.3 JSON序列化 2 异常处理2.1 throw 抛异常2.2 try ... catch 捕获异常…

Linux之Kafka保姆式详细安装教程

下载Kafka 《Kafka官网下载》 注意&#xff1a;下载的是二进制文件&#xff0c;不要下载源码&#xff01;这里可以采用第三方下载工具加速下载&#xff0c;如&#xff1a;迅雷等 上传到Linux服务器的/data/目录下进行解压 tar -zxvf是解压文件命令&#xff0c;-C表示把解压…

【C++学习笔记】1.6 引用

目录 &#x1f36f;1.6 引用 &#x1f95d;1. 引用的概念 &#x1f95d;2. 引用的特性 1、引用在定义时必须初始化 2、一个变量可以有多个引用 3、引用一旦引用一个实体&#xff0c;再不能引用其他实体 &#x1f95d;3. 常引用 1、取别名的原则&#xff1a;对原引用的…

数据查询大揭秘:收好几个模式化公式

欢迎来到数据查询大揭秘&#xff01;今天&#xff0c;我将与大家分享一些宝贵的秘诀和技巧&#xff0c;让你轻松应对数据查询的挑战。准备好了吗&#xff1f;收起你的笔记本和便签纸&#xff0c;因为我即将为你介绍几个模式化公式&#xff0c;让你事半功倍地完成数据查询任务&a…

湖北文理学院工程能力实训开班!

为深化校企合作&#xff0c;产教融合助力新工科建设&#xff0c;提升学生工程实践能力&#xff0c;电巢工程能力实训班按照不同岗位类别&#xff0c;匹配对应的企业岗位任职能力要求对学生开展分级培养&#xff0c;以产业需求为导向&#xff0c;培养创新型、应用型人才。 7月3…

open3D cmake+win10+vs2019编译

已经采用python版open3D实现和验证了功能&#xff0c;但是在C迁移上却遇到了不少问题&#xff1a; 1、可能是与本地的编译器存在差异&#xff0c;在使用open3D git上的winows版本时&#xff0c;存在地址访问冲突和std::bad_alloc等问题。前者在适用IO读写时必现&#xff0c;后者…

【Git】Windows如何运行.sh脚本文件

在Windows系统中运行.sh脚本需要借助第三方工具&#xff0c;比如Git Bash、Cygwin或WSL&#xff08;Windows Subsystem for Linux&#xff09;等。 以下是使用Git Bash运行.sh脚本的步骤&#xff1a; 安装Git Bash&#xff1a;从Git官方网站&#xff08;https://git-scm.com/…

【Ubuntu学习MySQL——MySQL基本操作命令】

1.创建数据库 2.删除数据库 3.选择数据库 4. 创建数据表 5.删除数据表 6.往数据表中插入数据 7.从数据表中查询数据 SELECT column_name,column_name FROM table_name [WHERE Clause] [LIMIT N][ OFFSET M]""" 查询语句中你可以使用一个或者多个表&#xff0c…

SpringMVC源码-DispatcherServlet

一、SpringMVC请求处理流程 DispatcherServlet&#xff1a;DispatcherServlet是SpringMVC中的前端控制器&#xff0c;负责接收request并将request转发给对应的处理组件。HandlerMapping&#xff1a;HanlerMapping是SpringMVC中完成url到Controller映射的组件。Handler&#xff…

智能汽车时代,产业如何“软硬兼施”

摘要&#xff1a; 智能汽车时代&#xff0c;以车用芯片、基础软件为代表的卡脖子关键技术&#xff0c;牵动着国内整个汽车供应链的安全。“软硬兼施”正成为从企业到汽车全行业的共同重大行动。 汽车产业链、供应链安全问题近两年已经引起全行业前所未有的关注。进入智能汽车时…

互联网医院资质申请难吗|互联网医院+医药机构

互联网医院牌照申请的具体流程可能因国家和地区的法规和政策而有所不同。下面是一个一般性的流程介绍&#xff1a;   准备材料&#xff1a;根据当地的法规和政策要求&#xff0c;准备申请互联网医院牌照所需要的相关材料。这些材料可能包括但不限于&#xff1a;公司注册证明、…