设计模式 -- 访问者模式(Visitor Pattern)

1 问题引出

1.1 测评系统的需求

        将观众分为男人和女人,对歌手进行测评,当看完某个歌手表演后,得到他们对该歌手不同的评价(评价 有不同的种类,比如 成功、失败 等)

1.2 传统方式解决

  • 如果系统比较小,还是 ok 的,但是考虑系统增加越来越多新的功能时,对代码改动较大,违反了 ocp 原则, 不利于维护
  • 扩展性不好,比如 增加了 新的人员类型,或者管理方法,都需要较多的变化

2 基本介绍

  1. 访问者模式(Visitor Pattern),封装一些作用于某种数据结构的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

  2. 主要将数据结构与数据操作分离,解决 数据结构和操作耦合性问题

  3. 访问者模式的基本工作原理是:在被访问的类里面加一个对外提供接待访问者的接口

  4. 访问者模式主要应用场景是:需要对一个对象结构中的对象进行很多不同操作(这些操作彼此没有关联),同时需要避免让这些操作"污染"这些对象的类,可以选用访问者模式解决。

  5. 访问者模式是一种行为型设计模式

3 原理结构图

3.1 类图

3.2 说明

  1. Visitor 是抽象访问者,为该对象结构中的 ConcreteElement 的每一个类声明一个 visit 操作

  2. ConcreteVisitor :是一个具体的访问值 实现每个有 Visitor 声明的操作,是每个操作实现的部分.

  3. ObjectStructure 能枚举它的元素, 可以提供一个高层的接口,用来允许访问者访问元素

  4. Element 定义一个 accept 方法,接收一个访问者对象

  5. ConcreteElement 为具体元素,实现了 accept 方法

4 应用实例

4.1 类图

4.2 代码实现

Action

public abstract class Action {// 得到男性测评public abstract void getManResult(Man man);// 得到女性测评public abstract void getWomanResult(Woman woman);
}

Client

public class Client {public static void main(String[] args) {ObjectStructure objectStructure = new ObjectStructure();objectStructure.attach(new Man());objectStructure.attach(new Woman());// 成功Success success = new Success();objectStructure.display(success);System.out.println("===============");Fail fail = new Fail();objectStructure.display(fail);System.out.println("=======待定的测评========");Wait wait = new Wait();objectStructure.display(wait);}}

Fail

public class Fail extends Action {@Overridepublic void getManResult(Man man) {System.out.println(" 男人给的评价该歌手很失败  !");}@Overridepublic void getWomanResult(Woman woman) {System.out.println("女给的评价该歌手很失败 !");}}

Man

public class Man extends Person {@Overridepublic void accept(Action action) {action.getManResult(this);}}

ObjectStructure

public class ObjectStructure {private List<Person> persons = new LinkedList<>();// 添加到listpublic void attach(Person p) {persons.add(p);}/ 删除public void detach(Person p) {persons.remove(p);}// 显示测评结果public void display(Action action) {for(Person p: persons) {p.accept(action);}}
}

Person

public abstract class Person {// 提供一个方法,让访问者可以访问public abstract void accept(Action action);
}

Success

public class Success extends Action {@Overridepublic void getManResult(Man man) {System.out.println(" 男人给的评价该歌手很成功 !");}@Overridepublic void getWomanResult(Woman woman) {System.out.println(" 女人给的评价该歌手很成功  !");}}

Wait

public class Wait extends Action {@Overridepublic void getManResult(Man man) {System.out.println(" 男人给的评价该歌手待定 ");}@Overridepublic void getWomanResult(Woman woman) {System.out.println(" 女人给的评价该歌手待定");}}

Woman

public class Woman extends Person{@Overridepublic void accept(Action action) {action.getWomanResult(this);}}

说明:

        这里使用到了双分派,即首先在客户端程序中,将具体状态作为参数传递Woman中(第一次分派),然后Woman 类调用作为参数的"具体方法”中方法getWomanResult,同时将自己(this)作为参数传入,完成第二次的分派。

拓展:

        双分派是一种设计模式,它允许在运行时根据两个对象的类型来选择执行合适的函数或方法。在理解双分派之前,需要了解单分派和双分派的区别。单分派是指根据对象的运行时类型来决定执行哪个对象的方法,而具体执行对象的哪个方法则根据方法参数的编译时类型决定。

5 优缺点

5.1 优点

  1. 可以在不修改已有代码结构的情况下,为对象结构中的各个元素添加新的操作,使得系统易于扩展。

  2. 访问者模式符合单一职责原则、让程序具有优秀的扩展性、灵活性非常高

  3. 访问者模式可以对功能进行统一,可以做报表、UI、拦截器与过滤器,适用于数据结构相对稳定的系统

5.2 缺点

  1. 具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的, 这样造成了具体元素变更比较困难

  2. 违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素

  3. 增加新的元素类型可能会导致需要修改抽象访问者接口,违背“开闭原则”。

6 应用场景

  • 场景一:当一个对象结构包含多种类型的元素,且这些元素需要执行不同的操作时,可以考虑使用访问者模式。
  • 场景二:如果需要对一个稳定的对象结构中的元素进行多种不同的操作,且这些操作经常变化,也适合应用访问者模式。

7 总结

        总而言之,访问者模式通过将操作从对象结构中分离出来,实现了在不改变对象结构的前提下,对其中的元素执行新的操作。这种模式适用于对象结构稳定,但操作经常变化的场景。尽管其实现较为复杂,但在合适的情况下使用访问者模式会带来显著的灵活性和可扩展性。

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

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

相关文章

安装 rocky9.4

涉及软件&#xff1a;virtualbox、rocky linux 9.4、mobaxterm virtualbox新建虚拟机&#xff0c;设置虚拟机配置 启动虚拟机&#xff0c;第一次会提示挂载虚拟光盘&#xff0c;选择下载的rocky linux 9.4。 选择第一项&#xff0c;安装rocky linux 9.4 进入安装设置&#…

VUE2.0 elementUI el-input-number 数据更新,视图不更新——基础积累

今天遇到一个问题&#xff0c;是关于el-input-number组件的&#xff0c;发现数据明明已经更改了&#xff0c;但是页面上组件输入框中还是之前的值。 比如上方输入框中&#xff0c;我输入120.5&#xff0c;就会出现下面的诡异现象 回显此值是120.779&#xff0c;但是页面上输入…

GNU的编译工具链

文章目录 GNU的编译工具链 GNU的编译工具链 预编译器cpp 编译器 cc1 汇编器 as 链接器 ld 其中cpp和cc1属于gcc的一部分&#xff0c;as和ld属于binutils的一部分。

STM32嵌入式面试知识点总结

一、STM32F1和F4的区别&#xff1f; 解答&#xff1a; 参看&#xff1a;STM32开发 – STM32初识内核不同&#xff1a;F1是Cortex-M3内核&#xff0c;F4是Cortex-M4内核&#xff1b;主频不同&#xff1a;F1主频72MHz&#xff0c;F4主频168MHz&#xff1b;浮点运算&#xff1a;…

【补-网络安全】日常运维(二)终端端口占用排查

文章目录 一、利用ipconfig、netstat 命令行统计二 、策略封禁IP 引言:检查频繁,第一步我们梳理完资产,第二步应该对资产终端进行一个排查,诊断把脉,了解清楚系统的端口占用及开放情况 一、利用ipconfig、netstat 命令行统计 1.先用ipconfig定位该终端的IP地址 2.明确IP地址后…

轴承知识大全,详细介绍(附3D图纸免费下载)

轴承一般由内圈、外圈、滚动体和保持架组成。对于密封轴承&#xff0c;再加上润滑剂和密封圈&#xff08;或防尘盖&#xff09;。这就是轴承的全部组成。 根据轴承使用的工作状况来选用不同类型的轴承&#xff0c;才能更好的发挥轴承的功能&#xff0c;并延长轴承的使用寿命。我…

逻辑学(Logic)

GPT-4o (OpenAI) 逻辑学是研究论证的原则和标准的学科&#xff0c;主要关注如何正确地推理和论证。从抓取股票日线数据到形成有效的分析&#xff0c;我们可以应用逻辑推理。 逻辑推理步骤&#xff1a; 1. 明确目标&#xff1a;我们要抓取股票的日线数据。 2. 分析需求&#x…

网络原理 - 初识

文章目录 局域网(LAN)广域网(WAN)网络设备IP地址格式 端口号格式 认识网络协议协议分层 OSI七层模型(只是理论,没有实际运用)TCP/IP五层&#xff08;或四层&#xff09;模型网络设备所在分层 封装和分用 计算机之间通过网络来传输数据&#xff0c;也称为网络通信。 根据网络互连…

18、Gemini-Pentest-v2

难度 中 目标 root权限 一个flag 靶机启动环境为VMware kali 192.168.152.56 靶机 192.168.152.63 信息收集 web测试 访问80端口 上面介绍了一下这个系统是一个内部系统&#xff0c;让员工查看他们的个人资料还可以导出为PDF 页面还有一个链接是UserList可以访问但是页面什…

前端【CSDN创作优化3】CSDN自定义模块:解决保存CSDN自定义模块时显示fail

【CSDN创作优化3】CSDN自定义模块&#xff1a;解决保存CSDN自定义模块时显示fail 写在最前面遇到的问题&#xff1a;保存CSDN自定义模块时显示fail1.符号问题&#xff1a;删除所有符号2.超出字符长度限制&#xff1a;压缩保存3.li模块不见了&#xff1a;小窗口正常显示元素 &am…

补题篇--codeforces

传送门&#xff1a;Problem - G - Codeforces 题意&#xff1a; 思路&#xff1a; 注意&#xff1a; n 的范围很小&#xff0c;大概率考察状态压缩 因此这个题可以考虑用 状压dp f[i][j] 表示状态为 i 的选法&#xff0c;以第 j 首歌为结尾的播放列表中的歌曲总数 f[ i | …

codeforces Round 970 (Div. 3)(A-F)

文章目录 [Codeforces Round 970 (Div. 3)](https://codeforces.com/contest/2008)A-[Sakurakos Exam](https://codeforces.com/contest/2008/problem/A)B-[Square or Not](https://codeforces.com/contest/2008/problem/B)C-[Longest Good Array](https://codeforces.com/cont…

Linux_kernel汇编04

一、温故知新 1、Uboot的操作 1&#xff09;Uboot的简介 需要确定一点&#xff0c;系统上电后&#xff0c;Uboot是第一个执行的系统软件。 类似PC机上的BIOS&#xff08;Basic Input Output System&#xff09; Uboot的核心功能&#xff1a; 【1】负责初始化硬件 【2】负责加载…

C++入门基础知识47——【关于C++函数】之函数参数及参数默认值

成长路上不孤单&#x1f60a;【14后&#xff0c;C爱好者&#xff0c;持续分享所学&#xff0c;如有需要欢迎收藏转发&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#xff01;&#xff01;&#xff01;&#xff01;&#xff…

MQ专题:消息积压相关问题和解决思路

一、如何发现消息出现了堆积 二、常见的原因及解决方案 三、消息出现了大量堆积&#xff0c;如何解决 四、建议

Android Studio gradle下载太慢了!怎么办?(已解决)

Android Studio&#xff01;你到底干了什么&#xff1f;&#xff01; 不能高速下载gradle&#xff0c;我等如何进行app编程&#xff1f;&#xff01; 很简单&#xff0c;我修改gradle地址不就是了。 找到gradle-wrapper.properties文件 修改其中distributionUrl的地址。 将 ht…

Axure健康助理小程序原型图70+页,医疗类高保真高交互模板

作品概况 页面数量&#xff1a;共 70 页 源文件格式&#xff1a;限 Axure RP 9/10&#xff0c;非app软件无源码 适用领域&#xff1a;医疗健康、健康助理 作品特色 本作品为健康助理小程序的Axure原型设计图&#xff0c;属于医疗健康项目&#xff0c;设计规范内容清晰&#…

SVN介绍和使用

一、SVN&#xff08;Subversion&#xff09; SVN 是一种版本控制系统&#xff0c;可以用于管理和控制文件的变更。以下是SVN的基本使用步骤&#xff1a; 安装SVN&#xff1a;首先&#xff0c;您需要在计算机上安装SVN客户端。您可以从Subversion官方网站下载安装程序&#xff…

SQL 五十周年:何去何从?

原文地址 https://www.infoworld.com/article/2337457/sql-at-50-whats-next-for-the-structured-query-language.html SQL 即使被生成式 AI 隐藏在幕后&#xff0c;也将继续在数据交互和使用方面发挥关键作用。 CREDIT: PAVEL L PHOTO AND VIDEO / SHUTTERSTOCK 1974 年 5 月…

苹果手机升级iOS 18时一直显示“正在检测更新”怎么办?

随着科技的不断发展&#xff0c;苹果手机的iOS系统也在不断迭代更新&#xff0c;为用户带来更加优质的使用体验。然而&#xff0c;在升级iOS 18的过程中&#xff0c;一些用户可能会遇到手机一直显示“正在检测更新”的问题&#xff0c;导致无法顺利完成系统升级。 这种情况不仅…