当前位置: 首页 > news >正文

Java设计模式之访问者模式

目录

定义

结构

案例

优点

缺点

使用场景

扩展

分派

案例实现须知

动态分派

静态分派

双分派


定义

封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。

结构

访问者模式包含以下主要角色:

  • 抽象访问者角色:定义了对每一个元素(Element)访问的行为,它的参数就是可以访问的元素,它的方法个数理论上来讲与元素类个数(Element的实现类个数)是一样的,从这点不难看出,访问者模式要求元素类的个数不能改变。
  • 具体访问者角色:给出对每一个元素类访问时所产生的具体行为。
  • 抽象元素角色:定义了一个接受访问者的方法(accept),其意义是指,每一个元素都要可以被访问者访问。
  • 具体元素角色: 提供接受访问方法的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法。
  • 对象结构角色:定义当中所提到的对象结构,对象结构是一个抽象表述,具体点可以理解为一个具有容器性质或者复合对象特性的类,它会含有一组元素(Element),并且可以迭代这些元素,供访问者访问。

案例

抽象访问类

//(参数为要访问的元素,且有几个元素就有几个方法)
public interface Person {//可以将feed方法名改为visit主要就是为了访问元素,具体实现可以在子类中实现void feed(Dog dog);void feed(Cat cat);
}

 抽象元素类

//(只定义一个被访问的方法即可)
public interface Animal {void accept(Person person);
}

具体元素类 

public class Dog implements Animal {@Overridepublic void accept(Person person) {person.feed(this);System.out.println("修勾接受了食物");}
}public class Cat implements Animal{@Overridepublic void accept(Person person) {person.feed(this);System.out.println("修猫接受了食物");}
}

具体访问类 

public class Owner implements Person{@Overridepublic void feed(Dog dog) {System.out.println("主人投喂食物");}@Overridepublic void feed(Cat cat) {System.out.println("主人投喂食物");}
}public class Someone implements Person{@Overridepublic void feed(Dog dog) {System.out.println("陌生人投喂了食物");}@Overridepublic void feed(Cat cat) {System.out.println("陌生人投喂了食物");}
}

对象结构角色 

public class Home {private List<Animal> animals = new ArrayList<>();public void action(Person person){for (Animal animal : animals) {animal.accept(person);}}public void addAnimal(Animal animal){animals.add(animal);}
}

测试 

public class Client {public static void main(String[] args) {Home home = new Home();home.addAnimal(new Dog());home.addAnimal(new Cat());home.action(new Owner());}
}

主人投喂食物

修勾接受了食物

主人投喂食物

修猫接受了食物

通过对象结构角色来访问具体元素。而访问者通过参数来控制。访问具体元素后调用访问者对应的方法。实现了访问者通过访问不同元素有不同的行为。

优点

  • 扩展性好。在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。(在案例中即Owner与Someone通过实现Person类重写了不同的功能)
  • 复用性好。通过访问者来定义整个对象结构通用的功能,从而提高复用程度。
  • 分离无关行为。通过访问者来分离无关的行为,把相关的行为封装在一起,构成一个访问者,这样每一个访问者的功能都比较单一。

缺点

  • 对象结构变化很困难。在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”。
  • 违反了依赖倒置原则。访问者模式依赖了具体类,而没有依赖抽象类。

使用场景

  • 对象结构相对稳定,但其操作算法经常变化的程序。
  • 对象结构中的对象需要提供多种不同且不相关的操作,而且要避免让这些操作的变化影响对象的结构。

扩展

访问者模式用到了一种双分派的技术。

分派

变量被声明时的类型叫做变量的静态类型,有些人又把静态类型叫做明显类型;而变量所引用的对象的真实类型又叫做变量的实际类型。比如 Map map = new HashMap() ,map变量的静态类型是 Map ,实际类型是HashMap 。根据对象的类型而对方法进行的选择,就是分派,分派又分为两种,即静态分派和动态分派。

静态分派:发生在编译时期,分派根据静态类型信息发生。静态分派对于我们来说并不陌生,方法重载就是静态分派。

动态分派:发生在运行时期,动态分派动态地置换掉某个方法。Java通过方法的重写支持动态分派。

案例实现须知

编译看左,运行看右。

即Map map = new HashMap(),map的真实类型在编译时期是不知道的,在运行后才会知道map的真实类型为HashMap。

对于重写的方法,通过子类对象访问到子类中的方法。

对于重载的方法,分派是根据静态类型进行的,参数类型在编译时期就已经确定了。

动态分派

public class Animal{void print(){System.out.println("animal");}
}public class Dog extends Animal{void print(){System.out.println("dog");}
}public class Cat extends Animal{@Overridevoid print() {System.out.println("cat");}
}public class Client {public static void main(String[] args) {Animal animal = new Animal();Animal dog = new Dog();Animal cat = new Cat();animal.print();dog.print();cat.print();}
}

animal

dog

cat

由于子类重写了print()方法,因此在运行时动态调用的是真实对象中的print()方法。即多态的实现。

静态分派

public class Animal{
}public class Dog extends Animal {
}public class Cat extends Animal {
}public class Execute {void print(Animal animal){System.out.println("animal");}void print(Dog dog){System.out.println("dog");}void print(Cat cat){System.out.println("cat");}
}public class Client {public static void main(String[] args) {Animal animal = new Animal();Animal dog = new Dog();Animal cat = new Cat();Execute execute = new Execute();execute.print(animal);execute.print(dog);execute.print(cat);}
}

animal

animal

animal

对应实现须知中的重载方法部分,对于execute.print()方法,参数dog与cat在编译时期就已经确定了他们的类型是静态类型Animal,因此在运行时并不会通过new Dog()与new Cat()在对dog与cat动态分派

双分派

所谓双分派技术就是因为重载在选择一个方法的时候,不仅仅要根据消息接收者(即上例中的execute运行时的真实类型)的运行时区别,还要根据参数(即参数在运行时的真实类型)的运行时区别。

public class Animal{void accept(Execute execute){execute.print(this);}
}public class Dog extends Animal {@Overridevoid accept(Execute execute) {execute.print(this);}
}public class Cat extends Animal {@Overridevoid accept(Execute execute) {execute.print(this);}
}public class Execute {void print(Animal animal){System.out.println("animal");}void print(Dog dog){System.out.println("dog");}void print(Cat cat){System.out.println("cat");}
}public class Client {public static void main(String[] args) {Execute execute = new Execute();Animal animal = new Animal();Animal dog = new Dog();Animal cat = new Cat();animal.accept(execute);dog.accept(execute);cat.accept(execute);}
}

animal

dog

cat

重载与重写相结合,先进行子类中重写的方法,这里执行第一次分派是动态分派,子类实现方法中将自身作为参数去执行重载方法,完成第二次分派

双分派实现动态绑定的本质,就是在重载方法委派的前面加上了继承体系中覆盖的环节,由于覆盖是动态的,所以重载就是动态的了。

相关文章:

Java设计模式之访问者模式

目录 定义 结构 案例 优点 缺点 使用场景 扩展 分派 案例实现须知 动态分派 静态分派 双分派 定义 封装一些作用于某种数据结构中的各元素的操作&#xff0c;它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作。 结构 访问者模式包含以下主要角色…...

PySide/PYQT如何用Qt Designer和代码来设置文字属性,如何设置文字颜色?

文章目录 📖 介绍 📖🏡 环境 🏡📒 实现方法 📒📝 Qt Designer设置📝 代码📖 介绍 📖 本人介绍如何使用Qt Designer/代码来设置字体属性(包含字体颜色) 🏡 环境 🏡 本文使用Pyside6来进行演示📒 实现方法 📒 📝 Qt Designer设置 首先打开Qt De…...

ubuntu 设置最大带宽

背景 近日做实验&#xff0c;需要限制一些机子的带宽以达到模拟的效果。在网上搜索了一阵子&#xff0c;结合自己实操的经验&#xff0c;潦草写下这篇文章&#xff0c;供自己与有需要的人参考。 环境&#xff1a; Ubuntu 22.04.1 LTS 安装 wondershaper 和 speedtest-cli w…...

如何在 Python 中执行 MySQL 结果限制和分页查询

Python MySQL 限制结果 限制结果数量 示例 1: 获取您自己的 Python 服务器 选择 “customers” 表中的前 5 条记录&#xff1a; import mysql.connectormydb mysql.connector.connect(host"localhost",user"您的用户名",password"您的密码"…...

Django配置文件,request,链接mysql方法,Orm简介

三板斧问题(views.py) HttpResponse # 返回的是字符串render # 渲染一个HTML静态文件&#xff0c;模板文件redirect # 重定向的 在视图文件中得视图函数必须要接收一个形参request&#xff0c;并且&#xff0c;视图函数也要有返回值&#xff…...

ubuntu下载各个版本chrome方法

Ubuntu/debian 在这里面找版本 https://unix.stackexchange.com/a/612981然后添充进去 http://dl.google.com/linux/chrome/deb/pool/main/g/google-chrome-stable/google-chrome-stable_[HERE_THE_FULL_VERSION]_amd64.deb比如&#xff1a;https://dl.google.com/linux/chro…...

Http状态码502常见原因及排错思路(实战)

Http状态码502常见原因及排错思路 502表示Bad Gateway。当Nginx返回502错误时&#xff0c;通常表示Nginx作为代理服务器无法从上游服务器&#xff08;如&#xff1a;我们的后端服务器地址&#xff09;获取有效的响应。导致这种情况的原因有很多&#xff1a; 后端服务器故障ngin…...

国际阿里云:无法ping通ECS实例公网IP的排查方法!!!

无法ping通ECS实例的原因较多&#xff0c;您可以参考本文进行排查。 问题现象 本地客户端无法ping通目标ECS实例公网IP&#xff0c;例如&#xff1a; 本地客户端为Linux系统&#xff0c;ping目标ECS实例公网IP时无响应&#xff0c;如下所示&#xff1a; 本地客户端为Windo…...

Nginx缓存基础

1 nginx缓存的流程 客户端需要访问服务器的数据时&#xff0c;如果都直接向服务器发送请求&#xff0c;服务器接收过多的请求&#xff0c;压力会比较大&#xff0c;也比较耗时&#xff1b;而如果在nginx缓存一定的数据&#xff0c;使客户端向基于nginx的代理服务器发送请求&…...

【数据结构】Lambda

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;浅谈数据结构 &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; Lambda表达式 1. 背景1.1 语法1.2 函…...

力扣labuladong——一刷day28

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、力扣380. O(1) 时间插入、删除和获取随机元素二、力扣710. 黑名单中的随机数 前言 常数时间删除-查找数组中的任意元素&#xff0c;且随机访问概率一致 如果…...

2023年CCF非专业级别软件能力认证第二轮 (CSP-S)提高级C++语言试题

2023年CCF非专业级别软件能力认证第二轮 &#xff08;CSP-S&#xff09;提高级C语言试题 编程题第 1 题 问答题 密码锁&#xff08;lock&#xff09; 题目描述 小Y有一把五个拨圈的密码锁。如图所示&#xff0c;每个拨圈上是从0到9的数字。每个拨圈都是从0到9的循环&#xf…...

华为ensp:静态默认路由

静态路由 到r2 上的系统视图模式 下一跳为1.1.1.2 ip route-static 192.168.2.0 255.255.255.0 1.1.1.2 如果找2网段下一跳为1.1.1.2接口 默认路由 到r3上做的是默认路由 ip route-static 0.0.0.0 0 1.1.1.1 所有的流量去找1.1.1.1 查看效果 只要做完完整的路由就可…...

xss 通过秘籍

终极测试代码 <sCr<ScRiPt>IPT>OonN"\/(hrHRefEF)</sCr</ScRiPt>IPT> 第一关&#xff08;没有任何过滤&#xff09; 使用终极测试代码&#xff0c;查看源码 发现没有任何过滤&#xff0c;直接使用javascrupt中的alert弹框 <script>aler…...

Kibana使用Watcher监控服务日志并发送飞书报警(Markdown)

Watcher是什么 Kibana Watcher 是 Elasticsearch 的监控和告警工具&#xff0c;它允许你设置和管理告警规则以监控 Elasticsearch 数据和集群的状态。Kibana Watcher 可以监测各种指标和数据&#xff0c;然后在满足特定条件时触发警报。它提供了一种强大的方式来实时监控 Elas…...

Flutter笔记:光影动画按钮、滚动图标卡片组等

Flutter笔记 scale_design更新&#xff1a;光影动画按钮、滚动图标卡片组 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_28550263…...

【论文】利用移动性的比例公平蜂窝调度测量和算法

&#xff08;一支笔一包烟&#xff0c;一节论文看一天 &#xff09;&#xff08;一张纸一瓶酒&#xff0c;一道公式推一宿&#xff09; 摘要1. 引言2. 相关工作3. 模型和问题公式4. 预测FPF调度 &#xff08; P F &#xff09; 2 S &#xff08;PF&#xff09;^2S &#xff08;…...

内存条选购注意事项(电脑,笔记本)

电脑内存条的作用、选购技巧以及注意事项详解 - 郝光明的个人空间 - OSCHINA - 中文开源技术交流社区 现在的电脑直接和内存条联系 电脑上的所有输入和输出都只能依靠内存条 现在买双条而不是单条 买两个相同的内存条最好 笔记本先分清是低电压还是标准电压&#xff0c;DD…...

ChatGPT 宕机?OpenAI 将中断归咎于 DDoS 攻击

您的 ChatGPT 已关闭吗&#xff1f;您是否遇到 ChatGPT 问题&#xff0c;例如连接问题或遇到“长响应时出现网络错误”&#xff1f;– ChatGPT 遭受了一系列 DDoS 攻击&#xff0c;显然是由匿名苏丹组织策划的。 OpenAI 的 ChatGPT 是一款流行的人工智能聊天机器人&#xff0c;…...

go单元格测试

编写单元测试&#xff08;Unit Test&#xff09;是一种测试方法&#xff0c;用于验证代码中的单个功能单元&#xff08;通常是函数或方法&#xff09;是否按照预期工作。以下是编写单元测试的一般步骤&#xff1a; 1. 创建测试文件&#xff1a;在项目的测试目录中创建一个新的…...

mysql如何对比备份数据与线上数据_编写自动化校验脚本

用mysqldump生成可比对备份需加--skip-extended-insert、--order-by-primary、--skip-comments、--no-tablespaces四参数&#xff1b;线上数据须用mysql -N -s -r直连导出TSV&#xff0c;再转为同格式INSERT后diff比对。用 mysqldump 生成可比对的备份快照直接拿原始 mysqldump…...

解锁Steam游戏新体验:开源成就管理工具深度解析

解锁Steam游戏新体验&#xff1a;开源成就管理工具深度解析 【免费下载链接】SteamAchievementManager A manager for game achievements in Steam. 项目地址: https://gitcode.com/gh_mirrors/st/SteamAchievementManager 你是否曾因为一个难以获得的成就而反复尝试同一…...

局域网视频软件BeeWorks Meet

对于必须在内网进行高清视频沟通的场景&#xff0c;BeeWorks Meet 是一款定位清晰、功能全面的私有化视频会议解决方案。它最大的特点在于&#xff0c;能将所有会议数据都安全地保留在企业内部网络&#xff0c;让企业对自己的核心会议内容拥有完全的自主权。&#x1f4cc; BeeW…...

26年前端面试新时代,问了几个AI题没人会怎么给offer???

当“你会不会用Copilot”成了第一题&#xff0c;全场沉默的那三秒&#xff0c;我看到了普通前端的末日。上周&#xff0c;朋友圈被一位36岁老哥的帖子刷屏了。他说自己已经摸清了“前端AI”面试的拷打套路&#xff0c;从被问到卡壳&#xff0c;到能跟面试官聊AI工程化的落地细节…...

Meta推出Muse Spark,AI领域再掀波澜

Meta告别旧模型&#xff0c;Muse Spark闪亮登场周三&#xff0c;Meta宣布推出Muse系列的首个AI模型——Muse Spark&#xff0c;这标志着Meta彻底告别了之前在开源Llama模型系列上的工作。Llama系列模型在用户和独立大语言模型&#xff08;LLM&#xff09;排名中反响平平&#x…...

别再只用Seurat分群了!用hdWGCNA给你的单细胞数据挖掘基因共表达模块(附INH神经元实战代码)

突破单细胞分群瓶颈&#xff1a;用hdWGCNA挖掘INH神经元功能模块的完整指南 当你完成单细胞转录组数据的Seurat标准分析流程&#xff0c;得到清晰的细胞聚类分群结果时&#xff0c;兴奋之余是否也感到一丝迷茫&#xff1f;知道细胞类型&#xff08;cell_type&#xff09;只是起…...

AI软件研发成本飙升的真相:3个被忽视的隐性成本源,今天不查明天多烧47%预算!

第一章&#xff1a;AI原生软件研发成本优化实战技巧 2026奇点智能技术大会(https://ml-summit.org) AI原生软件的研发成本常被模型训练开销主导&#xff0c;但实际可观测的浪费更多来自推理服务冗余、提示工程低效、以及缺乏细粒度资源编排。聚焦可落地的降本路径&#xff0c;…...

2026年04月10日最热门的开源项目(Github)

根据本期榜单的数据分析&#xff0c;我们可以从几个角度进行探讨&#xff0c;包括项目的语言、介绍、当前Stars及热度等。 1. 项目语言分布 此榜单中的项目主要集中在Python和JavaScript等常用语言上&#xff0c;其中Python项目数量较多。可以观察到Python的丰富生态和广泛应…...

GyverWire:嵌入式轻量级通用串行通信框架

1. GyverWire&#xff1a;面向嵌入式系统的轻量级、高鲁棒性通用串行通信框架GyverWire 是一款专为资源受限嵌入式平台&#xff08;尤其是 Arduino 生态&#xff09;设计的底层通信库&#xff0c;其核心目标并非实现某一种特定物理层协议&#xff0c;而是提供一个可复用、可扩展…...

用phpstudy在Win11上快速搭建DVWA:一个视频+这篇图文就够了

Win11下DVWA靶场极速搭建指南&#xff1a;phpstudy全流程详解与避坑手册 每次在本地搭建渗透测试环境时&#xff0c;最头疼的就是各种组件的版本冲突和配置问题。直到发现了phpstudy这个神器&#xff0c;配合DVWA靶场&#xff0c;终于能实现一键式部署。本文将带你用最简洁的步…...