java设计模式学习之【访问者模式】

文章目录

  • 引言
  • 访问者模式简介
    • 定义与用途
    • 实现方式
  • 使用场景
  • 优势与劣势
  • 在Spring框架中的应用
  • 电脑示例
  • 代码地址

引言

设想你是一个艺术馆的管理员,艺术馆里有各种各样的艺术品。每当有游客来访时,根据他们的兴趣,他们可能只想看画、雕塑或特定的展览。在这里,每位游客都有不同的“访问”行为,而艺术馆提供了他们所能“访问”的物品。在软件开发中,我们经常遇到需要对一个复杂的对象结构(如一个元素集合)执行不同操作的情况,而不希望修改对象的类。访问者模式提供了一种将操作逻辑与对象结构分离的方法,使得我们可以在不修改已有程序结构的情况下,向程序添加新的操作。

访问者模式简介

定义与用途

访问者模式(Visitor Pattern)是一种行为型设计模式,它允许你在不改变各元素类的前提下,定义作用于这些元素的新操作。它使用一种访问者类,改变元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者变化而变化。

实现方式

实现访问者模式通常涉及以下几个关键组件:

  • 访问者(Visitor)接口: 定义了对每一种元素(Element)类访问的操作。
  • 具体访问者(Concrete Visitor): 实现了访问者接口的类,定义了对每一种元素的具体访问行为。
  • 元素(Element)接口: 定义了一个接受访问者(accept)的方法。
  • 具体元素(Concrete Element): 实现了元素接口,其方法 accept 通常将自己作为参数传递给访问者的访问方法。

使用场景

访问者模式适用于以下场景:

  • 当一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象执行一些依赖于其具体类的操作。
  • 当需要对一个复杂的对象结构执行很多不相关的操作,而你不想在这些操作污染这些对象的类时。访问者可以将相关的操作组织在一个类中。
  • 当多个对象间存在一种“双重分派”关系时。即想根据两个对象的实际类型决定执行的操作。

例如:

  • 文档解析器: 文档结构中包含多种类型的元素,如文本、图片和表格。访问者模式可以用来实现文档的渲染、格式校验或者内容提取等操作。
  • 保险评估工具: 对不同类型的保险单执行风险评估和报价。每种保险单都有不同的风险评估算法,而所有算法都可以通过访问者模式来实现。
  • 公园管理系统: 一个公园包含多种类型的景点,如游乐场、植物园和博物馆。访问者模式可以用来实现不同访客对不同景点的不同访问行为,例如儿童、成人和园艺师。

优势与劣势

  • 优势
    • 增加新的操作很容易,只需添加一个新的访问者即可。
    • 将相关的操作集中到一个访问者中,而不是分散在多个元素类中。
  • 劣势
    • 增加新的元素类变得困难,每增加一个新的元素类,每一个访问者都可能需要修改。
    • 具体元素对访问者公开细节,违反了封装原则。

在Spring框架中的应用

在Spring框架中,BeanDefinitionVisitor 是访问者模式的一个实际应用例子,它用于访问和修改 BeanDefinition 对象。BeanDefinition 对象包含了Spring容器中bean的配置信息,如类名、属性值和构造函数参数。作用与用途:
BeanDefinitionVisitor 主要用于在Spring容器启动过程中修改已经加载的 BeanDefinition。它通过访问者模式允许开发者编写自定义逻辑来检查和修改 BeanDefinition,而不需要修改 BeanDefinition 的源代码。如何工作:
访问Bean定义: BeanDefinitionVisitor 遍历Bean定义中的属性值和构造函数参数等信息。
修改Bean定义: 它可以根据需要修改这些信息,例如解析占位符、应用属性编辑器或者更改属性值。
扩展性和灵活性: 开发者可以扩展 BeanDefinitionVisitor 类并覆盖相应的方法来实现自定义访问和修改逻辑。
使用场景:
属性占位符替换: PropertyPlaceholderConfigurer 是Spring中一个常见的使用 BeanDefinitionVisitor 的例子。它在容器启动时解析并替换属性文件中的占位符。
属性编辑器应用: 自定义 BeanDefinitionVisitor 可以用于在bean属性赋值之前应用自定义属性编辑器,进行类型转换或者其他预处理操作。
条件配置: 通过检查 BeanDefinition 的详细信息,BeanDefinitionVisitor 可以实现条件配置,根据不同的环境或条件选择性地修改或激活bean。
实现自定义BeanDefinitionVisitor:
要实现自定义的 BeanDefinitionVisitor,可以继承 BeanDefinitionVisitor 类,并重写 visitXXX 方法来实现特定的访问和修改逻辑。然后在容器启动过程中,或者作为 BeanFactoryPostProcessor 的一部分应用这个访问者到需要的 BeanDefinition 上。

电脑示例

在这里插入图片描述
步骤 1:定义代表元素的接口

public interface ComputerPart {public void accept(ComputerPartVisitor computerPartVisitor);
}

ComputerPart 接口定义了 accept 方法,所有具体的计算机部件类将实现这个接口,以允许访问者访问它们。

步骤 2:创建扩展上述类的具体类

public class Keyboard implements ComputerPart {@Overridepublic void accept(ComputerPartVisitor computerPartVisitor) {computerPartVisitor.visit(this);}
}

Keyboard 是一个具体的 ComputerPart,实现了 accept 方法,允许访问者访问键盘。

public class Monitor implements ComputerPart {@Overridepublic void accept(ComputerPartVisitor computerPartVisitor) {computerPartVisitor.visit(this);}
}

Monitor 是另一个具体的 ComputerPart,实现了 accept 方法,允许访问者访问显示器。

public class Mouse implements ComputerPart {@Overridepublic void accept(ComputerPartVisitor computerPartVisitor) {computerPartVisitor.visit(this);}
}

Mouse 是另一个具体的 ComputerPart,实现了 accept 方法,允许访问者访问鼠标。

public class Computer implements ComputerPart {ComputerPart[] parts;public Computer(){parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()};		} @Overridepublic void accept(ComputerPartVisitor computerPartVisitor) {for (ComputerPart part : parts) {part.accept(computerPartVisitor);}computerPartVisitor.visit(this);}
}

Computer 是一个复合的 ComputerPart,它包含其他部件。它的 accept 方法首先让访问者访问它的每个部分,然后访问计算机本身。

步骤 3:定义代表访问者的接口

public interface ComputerPartVisitor {public void visit(Computer computer);public void visit(Mouse mouse);public void visit(Keyboard keyboard);public void visit(Monitor monitor);
}

ComputerPartVisitor 接口定义了对每种类型的 ComputerPart 的访问操作。

步骤 4:创建实现上述类的具体访问者

public class ComputerPartDisplayVisitor implements ComputerPartVisitor {@Overridepublic void visit(Computer computer) {System.out.println("展示电脑。");}@Overridepublic void visit(Mouse mouse) {System.out.println("展示鼠标。");}@Overridepublic void visit(Keyboard keyboard) {System.out.println("展示键盘。");}@Overridepublic void visit(Monitor monitor) {System.out.println("展示显示器。");}
}

ComputerPartDisplayVisitor 是一个具体的访问者,它定义了如何展示每个部件。

步骤 5:使用 ComputerPartDisplayVisitor 来展示计算机的部件

public class VisitorPatternDemo {public static void main(String[] args) {ComputerPart computer = new Computer();computer.accept(new ComputerPartDisplayVisitor());}
}

在这里插入图片描述

在这个演示类中,我们创建了一个 Computer 对象并用 ComputerPartDisplayVisitor 来展示它的各个部件。

这个示例演示了访问者模式如何使得你可以定义新的操作而无需改变其操作的元素的类。通过这种方式,ComputerPartDisplayVisitor 可以添加新的展示行为而无需修改 ComputerPart 接口或其具体类的任何代码。这使得在不改变已有代码结构的前提下增加新的操作变得容易,从而提高了代码的可维护性和可扩展性。

代码地址

23种设计模式相关代码后续会逐步提交到github上,方便学习,欢迎指点:
代码地址
https://github.com/RuofeiSun/lf-23Pattern

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

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

相关文章

【开源】基于Vue+SpringBoot的房屋出售出租系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 房屋销售模块2.2 房屋出租模块2.3 预定意向模块2.4 交易订单模块 三、系统展示四、核心代码4.1 查询房屋求租单4.2 查询卖家的房屋求购单4.3 出租意向预定4.4 出租单支付4.5 查询买家房屋销售交易单 五、免责说明 一、摘…

spring security oauth2搭建认证服务器

如图(上面图片的代码在业务项目中),第一步在独立的业务项目中,先获取授权码(也叫jsessionId)、获取授权码的路径就是 /oauth2/authorize,这个路径是oauth2的框架中被OAuth2AuthorizationEndpoin…

如何从RTP包的AP类型包,获取h265的PPS、SPS、VPS信息

ffmpeg播放rtp流,为了降低首开延迟,需要在SDP文件中指定PPS、SPS、VPS信息。抓包后发现wireshark无法解析AP包。需要自己进行AP包解析。RTP协议AP包格式如下: 根据如上信息,我们可以解析AP包,效果如下 40 01&#xff…

图像质量评估:使用 SSIM 计算图像相似性

在图像处理领域,衡量两幅图像之间相似性的一种常见方法是使用结构相似性指数(SSIM)。SSIM 是一种全参考的图像质量评估指标,它不仅考虑了图像的亮度、对比度,还考虑了结构信息。在本文中,我们将介绍一个使用…

【Vue2+3入门到实战】(13)插槽<slot>详细示例及自定义组件的创建与使用代码示例 详解

目录 一、学习目标1.插槽2.综合案例:商品列表 一、插槽-默认插槽1.作用2.需求3.问题4.插槽的基本语法5.代码示例6.总结 二、插槽-后备内容(默认值)1.问题2.插槽的后备内容3.语法4.效果5.代码示例 三、插槽-具名插槽1.需求2.具名插槽语法3.v-s…

【JAVA】使用OPENGL

从这个网址下载对应的库: LWJGL - Lightweight Java Game Libraryhttps://www.lwjgl.org/browse/release/3.3.3下载这个压缩包(实际上有很多版本3.3.3是比较新的版本:LWJGL - Lightweight Java Game Library): https…

关于log4j的那些坑

背景:工程中同时存在log4j.xml&log4j2.xml maven依赖如下: 此时工程实际使用的日志文件为log4j.xml 1、当同时设置log4j和log4j2的桥接依赖时 maven依赖如下: 此时启动会有警告日志: 点击告警日志链接:https://…

【Vue2 + ElementUI】el-table中校验表单

一. 案例 校验金额 阐述&#xff1a;校验输入的金额是否正确。如下所示&#xff0c;点击【编辑图标】会变为input输入框当&#xff0c;输入金额。当输入框失去焦点时&#xff0c;若正确则调用接口更新金额且变为不可输入状态&#xff0c;否则返回不合法金额提示 <templat…

计算机网络复习4

网络层——点到点 文章目录 网络层——点到点功能路由算法IPV4NAT 网络地址转换子网划分与子网掩码、CIDR地址解析协议ARP&#xff1a;根据IP地址找到MAC地址动态主机配置协议DHCP网际控制报文协议ICMPIPV6内部网关协议&#xff08;IGP&#xff09;外部网关协议(EGP) 功能 异构…

数字人直播系统——打破时空限制的新媒体时代

随着科技的不断进步&#xff0c;新媒体开始逐渐成为人们获取信息和娱乐的首选方式。其中&#xff0c;数字人直播系统作为一种创新的传媒形式&#xff0c;正以其独特的优势受到越来越多人的关注和喜爱。数字人直播系统通过将虚拟人物与现实世界紧密结合&#xff0c;打破了时间和…

SuperMap YashanDB联合解决方案发布,赋能更强大的地理智慧

近期&#xff0c;深圳计算科学研究院&#xff08;简称“深算院”&#xff09;携手超图软件集团&#xff08;简称“超图 ”&#xff09;重磅推出基于崖山数据库的空间数据管理解决方案&#xff0c;基于YashanDB空间数据库能力&#xff0c;与超图SuperMap GIS平台深度适配&#x…

【温故而知新】vue运用之探讨下单页面应用(SPA)与多页面应用(MPA)

一、概念 1.单页面应用SPA(Single page application) Vue单页面应用是一种采用Vue.js框架开发的Web应用程序,它仅有一个HTML文件,通过前端路由实现页面的切换和渲染。与传统的多页面应用相比,Vue单页面应用在用户体验和开发效率方面有着明显的优势。 在Vue单页面应用中…

计算机与人工智能:共创智能时代的新篇章

计算机与人工智能&#xff1a;共创智能时代的新篇章 在这个科技日新月异的时代&#xff0c;计算机与人工智能&#xff08;AI&#xff09;的结合正以前所未有的速度改变着世界。它们在各自的领域内飞速发展&#xff0c;而当这两者相遇时&#xff0c;它们产生了巨大的能量&#x…

C++ Qt开发:TableView与TreeView组件联动

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍TableView与TreeView组件联动的常用方法及灵活…

== 和 equals() 的区别

大家好&#xff0c;我是"java继父"伯约&#xff0c;这篇对大家有帮助的话求一个赞&#xff0c;另外文章末尾放了我从月入7k到现在3W的学习资料&#xff0c;大家可以去领一下&#xff08;无偿&#xff09;。 对于基本类型和引用类型的作用效果是不同的&#xff1a; …

再谈动态SQL

专栏精选 引入Mybatis Mybatis的快速入门 Mybatis的增删改查扩展功能说明 mapper映射的参数和结果 Mybatis复杂类型的结果映射 Mybatis基于注解的结果映射 Mybatis枚举类型处理和类型处理器 文章目录 专栏精选摘要引言正文动态sql标签ifchoose...when...otherwisewhere、…

【AI】阿里云免费GPU服务资源领取方法

首先&#xff0c;直接点击链接&#xff1a;阿里云免费试用 也可以复制链接到浏览器进行跳转&#xff1a;https://free.aliyun.com?userCodernbj0c1o 页面如下所示&#xff1a;这里的免费试用期限是3个月&#xff0c;给的资源点够我们试用V100 16G显存服务器300个小时&#xff…

作业--day38

1.定义一个Person类&#xff0c;包含私有成员&#xff0c;int *age&#xff0c;string &name&#xff0c;一个Stu类&#xff0c;包含私有成员double *score&#xff0c;Person p1&#xff0c;写出Person类和Stu类的特殊成员函数&#xff0c;并写一个Stu的show函数&#xff…

智慧工地云平台源码 支持二次开发、支持源码交付

智慧工地利用移动互联、物联网、云计算、大数据等新一代信息技术&#xff0c;彻底改变传统施工现场各参建方的交互方式、工作方式和管理模式&#xff0c;为建设集团、施工企业、监理单位、设计单位、政府监管部门等提供一揽子工地现场管理信息化解决方案。 通过人员管理、车辆管…

还在用Jekins?快来试试这款比Jekins简而轻的自动部署软件!

大家好&#xff0c;我是 Java陈序员。 在工作中&#xff0c;你是否遇到过团队中没有专业的运维&#xff0c;开发还要做运维的活&#xff0c;需要自己手动构建、部署项目&#xff1f; 不同的项目还有不同的部署命令&#xff0c;需要使用 SSH 工具连接远程服务器和使用 FTP 文件…