技术标签: java 如何使用访问者模式 Java_23种设计模式 设计模式 访问者模式
Java中除去有设计原则之外,还有23中设计模式。
这些模式都是前辈们一点一点积累下来,一直在改进,一直在优化的,而这些设计模式可以解决一些特定的问题。
并且在这些模式中,可以说是将语言的使用体现的淋漓尽致。
那我们今天要学习 行为型模式 中的 访问者模式 !
先来了解一下什么是访问者模式
通过百科,我们可以知道,这个模式是非常的难,但是我们还是得需要去学习
这个模式可以去做什么呢?比如说一个电视剧里面的角色,你看是一种样子,我们是另外一种样子。
访问者(Visitor)模式的定义:将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。它将对数据的操作与数据结构进行分离,是行为类模式中最复杂的一种模式。
访问者(Visitor)模式是一种对象行为型模式,其主要优点如下。
1. 扩展性好。能够在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。
2. 复用性好。可以通过访问者来定义整个对象结构通用的功能,从而提高系统的复用程度。
3. 灵活性好。访问者模式将数据结构与作用于结构上的操作解耦,使得操作集合可相对自由地演化而不影响系统的数据结构。
4. 符合单一职责原则。访问者模式把相关的行为封装在一起,构成一个访问者,使每一个访问者的功能都比较单一。
访问者(Visitor)模式的主要缺点如下。
1. 增加新的元素类很困难。在访问者模式中,每增加一个新的元素类,都要在每一个具体访问者类中增加相应的具体操作,这违背了“开闭原则”。
2. 破坏封装。访问者模式中具体元素对访问者公布细节,这破坏了对象的封装性。
3. 违反了依赖倒置原则。访问者模式依赖了具体类,而没有依赖抽象类。
首先来看一下角色:
1. 抽象访问者角色:定义一个访问具体元素的接口,为每个具体元素类对应一个访问操作 visit() ,该操作中的参数类型标识了被访问的具体元素。
2. 具体访问者角色:实现抽象访问者角色中声明的各个访问操作,确定访问者访问一个元素时该做什么。
3. 抽象元素角色:声明一个包含接受操作 accept() 的接口,被接受的访问者对象作为 accept() 方法的参数。
4. 具体元素角色:实现抽象元素角色提供的 accept() 操作,其方法体通常都是 visitor.visit(this) ,另外具体元素中可能还包含本身业务逻辑的相关操作。
5. 对象结构角色:是一个包含元素角色的容器,提供让访问者对象遍历容器中的所有元素的方法,通常由 List、Set、Map 等聚合类实现。
知道了这些之后,我们自己来实现一个简单的访问者模式的例子
我们先来将这个抽象元素角色来定义一下,这里注意,这个是一个接口
然后我们再来定义一下抽象访问者
然后我们将这个抽象元素角色的方法 accept() 方法写一下
第二步,我们将具体的访问者创建一下,这里我们创建2个就好了
当然啊,不可能实现一个空接口,我们给之前的访问者接口定义方法
这里会报错,但是不要慌,每一个访问者都有很多个访问元素,所以,我们再去创建一下访问元素
创建好之后,我们去实现一下 Element 抽象元素的接口
接着我们返回到这个访问者,我们先写它
A 访问者访问一下 a 这个元素,还有 b 这个元素,但是具体的方法并没有,我们接下来去定义
我们将两个方法定义好之后,我们再去看一下元素的 accept 方法,这个方法需要使用访问者去调用 visit 方法,传递的值的话,就是本身,我们来实现一下
有了这些还不够,我们还需要准备一个对象结构角色,这个东西主要是用来将所有的元素统一放在一个地方,这样方便访问者去查看
最后一步,我们搞一个测试,来测试一下这个
首先将对象结构弄好,然后将对象放进去,最后使用访问者进行访问
运行看看结果
是OK的啊,大家自己可以再去实例化一个访问者B,看看效果
OK,就到这里,大家好好看一下。多多练习。有问题可以联系我QQ:2100363119
欢迎大家访问我的个人网站:lemon1234.com 感谢大家留言
文章浏览阅读244次。在说ClassCastException之前,先介绍下引用类型转换;引用类型转换分为向上转型和向下转型两种;向上转型:多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的;当父类引用指向一个子类对象时,便是向上转换;使用格式:父类类型 变量名 = new 子类类型();向下转型:父类类型向子类类型向下转换的过程,这个过程时强制;一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强..._enhancerbyspringcglib 报错 classcastexception类型转换异常
文章浏览阅读418次。What graphQL关于graphQL的介绍在网上有很多,但从核心上讲,是一门语言;进一步讲,是一门查询语言;再进一步讲,是一种API查询语言。有疑问?API还能查?API不是用来调用的吗?没错,这正是GraphQL的强大之处。Why graphQL我们在使用Rest接口时,接口返回的数据格式、数据类型都是后端预先定义好的,如果返回的数据格式并不是调用者所期望的,作为前端的人员可以通过以..._graphql query
文章浏览阅读2.7w次,点赞33次,收藏169次。离散系统的解析描述--建立差分方程1. 差分的定义移位序列:设有序列f(k), 则… , f(k+2), f(k+1), f(k-1),f(k-2),… 等称为f(k)的移位序列。差分运..._系统的差分方程
文章浏览阅读236次。八年磨一剑1.1 HBase 的前世今生关系型数据库的发展已经经历了 40 多年的历史了,而 HBase 以及大数据这套东 西的历史大概从 2006 年被认为是大数据的发起时期到现在,也就是 13 年左右 而已。那么,为什么会出现 HBase 以及 Hadoop 整体生态链的这些内容呢?这 是因为在大数据时代,传统数据库需要面对很多挑战,出现了数据量增..._hbase 2.2 2.1 对比
文章浏览阅读4.4k次。嵌入式硬盘录像机(DVR)与PC机一样,都存在硬盘文件系统。嵌入式DVR硬盘文件系统可分为两类,一是与PC机相同的FAT文件系统,第二种是嵌入式DVR生产厂家自行开发的,适合存储大容量媒体数据流的专业文件系统。 目前市场上,PC-based DVR一般基于Windows系统,文件系统一般采用NTFS或FAT32;而嵌入式 DVR所采用的文件系统则与厂商选择的嵌入式操作系统有密切的_dvr 设备通常使用什么文件系统来存储视频
文章浏览阅读1.2k次。问题mac地址在设备树写死,导致多个板卡在一个系统中mac地址冲突,打算采用uboot中的mac地址,出厂时手动设置不同mac_linux mac地址自动分配
文章浏览阅读477次。10月28日,在英特尔On技术创新峰会上,英特尔揭开了第12代英特尔 酷睿处理器产品家族的神秘面纱,推出了六款全新未锁频台式机处理器,其中包括全球性能出众的游戏处理器——第12代英特尔..._酷睿十二代发布
文章浏览阅读1.7w次,点赞3次,收藏19次。封装目录中所包含的文件 Api.js ApiIp.js ApiURL.jsApiIp.js文件的作用这个文件的作用主要是在开发环境和生产环境下调用不同的接口请求地址,生产环境下此文件的作用是动态的获取浏览器中的地址进行拼装,便可以动态的获取地址,不需要写死//获取当前的URL中的地址,同时携带端口号,不携带http://let projectAddrass = windo..._react封装请求api接口
文章浏览阅读8.1k次,点赞13次,收藏110次。如何寻找数据集?除了医疗领域之外,其他领域的数据集有时也很难获取,这就需要我们掌握一些常见的数据集搜集方法和常用资源。最近,Medium 上的一位博主介绍了多个常用的数据集获取来源:1 Awesome Data这是一个 GitHub 存储库,包含多个不同类别的数据集。链接:https://github.com/awesomedata/awesome-public-datasets2 Data Is Plural这是一个以电子表格形式展示的数据集资源,从 2015 年开始定期更新,最新一期是 20_如何在github上找数据集
文章浏览阅读86次。[luogu4035 JSOI2008] 球形空间产生器 (矩阵 高斯消元) 传送门题目描述有一个球形空间产生器能够在 nnn 维空间中产生一个坚硬的球体。现在,你被困在了这个 nnn 维球体中,你只知道球面上 n+1n+1n+1 个点的坐标,你需要以最快的速度确定这个 nnn 维球体的球心坐标,以便于摧毁这个球形空间产生器。输入输出格式输...
文章浏览阅读884次。Linux内存初始化说明mm_initmem_initfree_all_bootmem相关文章说明Kernel版本:4.0.0ARM处理器,Contex-A9,QEMU平台 上文完成了zone的初始化工作,接下来需要初始化伙伴系统(Buddy系统)。mm_init mm_init函数,主要对内核内存分配器进行初始化。start_kernel->mm_init/* * Set up kernel memory allocators */static void __init mm_div_round_up
文章浏览阅读3.2k次。python生成订单号或生成任意序列示例代码:import time# 生成订单号def get_order_code(): # 年月日时分秒+time.time()的后7位 order_no = str(time.strftime('%Y%m%d%H%M%S', time.localtime(time.time())) + str(time.time()).replace('.', '')[-7:]) return order_noprint(get_o_python 生成订单号