访问者模式的理解和实践

        在软件开发过程中,设计模式为我们提供了解决常见问题的最佳实践。访问者模式(Visitor Pattern)是行为设计模式之一,它将数据操作与数据结构分离,使得在不修改数据结构的前提下,能够定义作用于这些元素的新的操作。本文将详细讲解访问者模式的概念、原理、优缺点,并通过Java代码示例展示其在实际项目中的应用。

 

一、访问者模式的概念

        访问者模式是一种将数据操作与数据结构分离的设计模式。它通过将作用于某种数据结构中的各元素的操作封装起来,使得这些操作可以独立于数据结构进行变化。访问者模式使得我们能够在不修改数据结构的前提下,增加新的操作。

二、访问者模式的结构

        访问者模式包含以下几个角色:

  1. Visitor(访问者):接口或抽象类,声明了访问者对各个元素的操作方法。
  2. ConcreteVisitor(具体访问者):实现了Visitor接口或抽象类,具体实现了对各个元素的操作。
  3. Element(元素):接口或抽象类,声明了接受访问者的方法。
  4. ConcreteElement(具体元素):实现了Element接口或抽象类,存储数据,并实现了接受访问者的方法。
  5. ObjectStructure(对象结构):包含多个元素,可以迭代这些元素,并允许访问者访问这些元素。

三、访问者模式的原理

        访问者模式的原理是将操作从数据结构中分离出来,封装到访问者类中。数据结构中的每个元素都接受访问者对象,访问者对象通过访问这些元素来执行相应的操作。这样,当需要增加新的操作时,只需新增一个访问者类,而无需修改数据结构。

四、访问者模式的优缺点

优点

  1. 增加新的操作很容易:只需增加一个新的访问者类,而无需修改已有的数据结构。
  2. 将数据操作集中管理:访问者模式将相关的操作集中到一个访问者类中,便于管理。
  3. 分离了数据结构和操作:数据结构和操作不再耦合在一起,提高了系统的灵活性。

缺点

  1. 增加了类的数量:每增加一个新的操作,都需要增加一个新的访问者类,增加了类的数量。
  2. 破坏了封装:访问者需要访问被访问对象的内部结构,这在一定程度上破坏了封装性。
  3. 增加了系统复杂度:访问者模式的实现相对复杂,需要理解其工作原理,才能正确使用。

五、访问者模式的实践

        下面通过Java代码示例,展示访问者模式在实际项目中的应用。

示例背景

        假设我们有一个简单的员工管理系统,员工分为两类:工程师(Engineer)和经理(Manager)。我们需要实现两个操作:计算工资(CalculateSalary)和显示员工信息(DisplayInfo)。

代码实现

定义Element接口

// 定义Element接口
public interface Element {
    void accept(Visitor visitor);
}

定义具体元素类

// 定义工程师类
public class Engineer implements Element {
    private String name;
    private int salary;

    public Engineer(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public int getSalary() {
        return salary;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

// 定义经理类
public class Manager implements Element {
    private String name;
    private int salary;
    private int bonus;

    public Manager(String name, int salary, int bonus) {
        this.name = name;
        this.salary = salary;
        this.bonus = bonus;
    }

    public String getName() {
        return name;
    }

    public int getSalary() {
        return salary;
    }

    public int getBonus() {
        return bonus;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

定义Visitor接口

// 定义Visitor接口
public interface Visitor {
    void visit(Engineer engineer);
    void visit(Manager manager);
}

定义具体访问者类

// 定义计算工资访问者类
public class CalculateSalaryVisitor implements Visitor {

    @Override
    public void visit(Engineer engineer) {
        System.out.println("Engineer " + engineer.getName() + " salary: " + engineer.getSalary());
    }

    @Override
    public void visit(Manager manager) {
        int totalSalary = manager.getSalary() + manager.getBonus();
        System.out.println("Manager " + manager.getName() + " salary: " + totalSalary);
    }
}

// 定义显示信息访问者类
public class DisplayInfoVisitor implements Visitor {

    @Override
    public void visit(Engineer engineer) {
        System.out.println("Engineer: " + engineer.getName());
    }

    @Override
    public void visit(Manager manager) {
        System.out.println("Manager: " + manager.getName() + ", Bonus: " + manager.getBonus());
    }
}

定义ObjectStructure类

import java.util.ArrayList;
import java.util.List;

// 定义ObjectStructure类
public class ObjectStructure {
    private List<Element> elements = new ArrayList<>();

    public void addElement(Element element) {
        elements.add(element);
    }

    public void removeElement(Element element) {
        elements.remove(element);
    }

    public void accept(Visitor visitor) {
        for (Element element : elements) {
            element.accept(visitor);
        }
    }
}

客户端代码

public class Client {
    public static void main(String[] args) {
        ObjectStructure os = new ObjectStructure();

        os.addElement(new Engineer("John Doe", 70000));
        os.addElement(new Manager("Jane Smith", 80000, 10000));

        Visitor calculateSalaryVisitor = new CalculateSalaryVisitor();
        os.accept(calculateSalaryVisitor);

        System.out.println("------");

        Visitor displayInfoVisitor = new DisplayInfoVisitor();
        os.accept(displayInfoVisitor);
    }
}


运行结果

Engineer John Doe salary: 70000
Manager Jane Smith salary: 90000
------
Engineer: John Doe
Manager: Jane Smith, Bonus: 10000


总结

        访问者模式通过将操作从数据结构中分离出来,提高了系统的灵活性和可扩展性。它使得在不修改数据结构的前提下,能够增加新的操作。然而,访问者模式也增加了类的数量,破坏了封装,增加了系统的复杂度。因此,在实际应用中,我们需要根据具体需求权衡利弊,选择是否使用访问者模式。

        通过上面的示例,我们可以看到访问者模式在员工管理系统中的应用,通过定义不同的访问者类,实现了计算工资和显示员工信息的功能。这使得系统的操作更加灵活,易于扩展和维护。希望这篇文章能够帮助大家更好地理解访问者模式,并在实际项目中灵活运用。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Java 学习】面向程序的三大特性:封装、继承、多态

引言 1. 封装1.1 什么是封装呢&#xff1f;1.2 访问限定符1.3 使用封装 2. 继承2.1 为什么要有继承&#xff1f;2.2 继承的概念2.3 继承的语法2.4 访问父类成员2.4.1 子类中访问父类成员的变量2.4.2 访问父类的成员方法 2.5 super关键字2.6 子类的构造方法 3. 多态3.1 多态的概…

Burp与小程序梦中情缘

前言 在日常渗透工作中&#xff0c;有时需要对微信小程序进行抓包渗透&#xff0c;通过抓包&#xff0c;我们可以捕获小程序与服务器之间的通信数据&#xff0c;分析这些数据可以帮助我们发现潜在的安全漏洞&#xff0c;本文通过讲述三个方法在PC端来对小程序抓包渗透 文章目…

基于Qwen2-VL模型针对LaTeX OCR任务进行微调训练 - 原模型 多图推理

基于Qwen2-VL模型针对LaTeX OCR任务进行微调训练 - 原模型 多图推理 flyfish 输入 输出 [‘第一张图片是一幅中国山水画&#xff0c;描绘了一座山峰和周围的树木。第二张图片是一张现代照片&#xff0c;展示了一座山峰和周围的自然景观&#xff0c;包括水体和植被。’] fro…

R语言学习笔记-1

1. 基础操作和函数 清空环境&#xff1a;rm(list ls()) 用于清空当前的R环境。 打印输出&#xff1a;print("Hello, world") 用于输出文本到控制台。 查看已安装包和加载包&#xff1a; search()&#xff1a;查看当前加载的包。install.packages("package_na…

基本分页存储管理

一、实验目的 目的&#xff1a;熟悉并掌握基本分页存储管理的思想及其实现方法&#xff0c;熟悉并掌握基本分页存储管理的分配和回收方式。 任务&#xff1a;模拟实现基本分页存储管理方式下内存空间的分配和回收。 二、实验内容 1、实验内容 内存空间的初始化——可以由用户输…

如何将CSDN的文章保存为PDF?

目录 1、打开CSDN文章2、按F12或者鼠标右键选择检查并进入控制台3、在控制台输入以下代码4、然后回车&#xff08;Enter&#xff09;如果纵向显示不全就横向 1、打开CSDN文章 2、按F12或者鼠标右键选择检查并进入控制台 3、在控制台输入以下代码 (function(){ $("#side&q…

ur机器人ros-urdf

新建工作空间 mkdir -p ~/catkin_ws/src cd catkin_ws_ur5/src git clone -b melodic-devel https://github.com/ros-industrial/universal_robot.git cd .. rosdep update rosdep install --rosdistro melodic --ignore-src --from-paths src catkin_make source ~/catkin_ws…

A6688 JSP+MYSQL+LW+二手物品网上交易系统

二手物品网上交易系统的设计与实现 1.摘要2.开发目的和意义3.系统功能设计4.系统界面截图5.源码获取 1.摘要 摘 要 随着社会经济快速发展&#xff0c;互联网推动了电子商务业的迅速崛起。越来越多的人们喜欢在线进行商品的交易&#xff0c;尤其是对于二手物品的处理&#xff0…

深度学习day4|用pytorch实现猴痘病识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 &#x1f37a;要求&#xff1a; 训练过程中保存效果最好的模型参数。 加载最佳模型参数识别本地的一张图片。 调整网络结构使测试集accuracy到达88%&#x…

ISP(Image Signal Processor)——HDR技术总结

传统多帧融合技术 拍摄一系列不同曝光时长的图像帧&#xff08;LDR&#xff09;&#xff0c;然后使用融合算法进行融合成HDR图像。 融合算法可以分为两种 基于照度图估计的融合 基于照度估计需要拟合相机响应函数&#xff0c;详细可以参考如下论文&#xff1a; Recovering H…

首程控股再发停车资产类REITs,行业走向“资产管理模式”

伴随着资产证券化的快速发展&#xff0c;交易结构设置和底层资产类型也愈加丰富多样。 近日&#xff0c;首程控股完成“国君-首程控股智慧停车第二期资产支持专项计划”的正式发行。据了解&#xff0c;该产品的优先级利率为2.40%&#xff0c;发行规模达到人民币3.70亿元&#…

如何写出优秀的单元测试?

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 写出优秀的单元测试需要考虑以下几个方面&#xff1a; 1. 测试用例设计 测试用例应该覆盖被测试代码的不同场景和边界情况&#xff0c;以尽可能发现潜在的问题。…

PostgreSQL的学习心得和知识总结(一百六十四)|深入理解PostgreSQL数据库之在 libpq 中支持负载平衡

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《PostgreSQL数据库内核分析》 2、参考书籍&#xff1a;《数据库事务处理的艺术&#xff1a;事务管理与并发控制》 3、PostgreSQL数据库仓库…

批量合并多个Excel到一个文件

工作中&#xff0c;我们经常需要将多个Excel的数据进行合并&#xff0c;很多插件都可以做这个功能。但是今天我们将介绍一个完全免费的独立软件【非插件】&#xff0c;来更加方便的实现这个功能。 准备Excel 这里我们准备了两张待合并的Excel文件 的卢易表 打开的卢易表软件…

shell编程(完结)

shell编程&#xff08;完结&#xff09; 声明&#xff01; 学习视频来自B站up主 ​泷羽sec​​ 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章 笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其…

docker 容器相互访问

目前采用 network 方式 1. 创建自定义网络 docker network create network-group 如下 2. 相互访问的容器更改&#xff08;目前演示redis 以及netcore api 访问redis &#xff09; //redis 原有容器删除 跟之前区别就是加入 --network network-group docker run \ -p 6379:…

nVisual关于钉钉小程序打开项目及调试说明

关于钉钉小程序开发者工具的使用对于没有接触过的人可能比较陌生。如果需要部署钉钉小程序是需要对钉钉小程序开发者工具有一定的了解的&#xff0c;需要在此做部分上线前的测试及在开发者工具中上传项目包&#xff0c;故此做部分工具的解释。 分三部分来进行解释&#xff1a;…

免费下载 | 2024算网融合技术与产业白皮书

《2024算网融合技术与产业白皮书&#xff08;2023年&#xff09;》的核心内容概括如下&#xff1a; 算网融合发展概述&#xff1a; 各国细化算网战略&#xff0c;指引行业应用创新升级。 算网融合市场快速增长&#xff0c;算力互联成为投资新热点。 算网融合产业模式逐渐成型…

基于docker搭建pulsar和使用攻略

pulsar Pulsar是一个由yahoo公司于2016年开源的消息中间件&#xff0c;2018年成为Apache的顶级项目 我们先来看一下架构&#xff0c;从架构来看&#xff0c;和其他的消息中间件差不多&#xff0c;都是有消费者&#xff0c;生产者和broker,唯一一点不同的是pulsar的数据存储是…

[代码随想录16]二叉树的重新构造,路径总和,左下角的值

前言 关于二叉树的题目&#xff0c;我认为主要是把基础的思想掌握了&#xff0c;剩下的还是拼装和组合的题目&#xff0c;我们重要的就是学会一些基本的二叉思路&#xff0c;递归好还是迭代好&#xff0c;怎么递归和怎么迭代&#xff0c;二叉树的题目在面试过程中考的是挺多的&…