访问者模式-操作复杂对象结构

 商场里有许多的店铺,大致分为服装区、饮食区及休闲区,每天都会有络绎不绝的不同角色(打工人、学生、有钱人)的人来逛商场。商场想开发个系统用来模拟这些人的在这些店铺的行为。

public class SuperMarket {public static void main(String[] args) {List<PeopleRole> peopleRoles = new ArrayList<>();statisticsPeople(peopleRoles);Random random = new Random();for (PeopleRole peopleRole : peopleRoles) {peopleRole.showRole();int nextInt = random.nextInt();if (nextInt % 3 == 0) peopleRole.shopping(ShopPlace.food);else if (nextInt % 2 == 0) peopleRole.shopping(ShopPlace.clothing);else peopleRole.shopping(ShopPlace.relax);System.out.println("........................");}}static void statisticsPeople(List<PeopleRole> peopleRoles) {Random random = new Random();for (int i = 0; i < 10; i++) {int nextInt = random.nextInt();if (nextInt % 2 == 0) peopleRoles.add(PeopleRole.worker);else if (nextInt % 3 == 0) peopleRoles.add(PeopleRole.student);else peopleRoles.add(PeopleRole.rich);}}interface SuperMarketShopping {void showRole();void shopping(ShopPlace shopPlace);}enum PeopleRole implements SuperMarketShopping{worker { // 打工人@Overridepublic void showRole() {System.out.print("打工人:");}@Overridepublic void shopping(ShopPlace shopPlace) {switch (shopPlace) {case food:System.out.println("兰州拉面");break;case relax:System.out.println("看场电影");break;case clothing:System.out.println("去优衣库买T恤");break;}}},student { // 学生@Overridepublic void showRole() {System.out.print("学生:");}@Overridepublic void shopping(ShopPlace shopPlace) {switch (shopPlace) {case food:System.out.println("吃麻辣烫");break;case relax:System.out.println("去电玩城");break;case clothing:System.out.println("不买衣服,看一下");break;}}},rich { // 有钱人@Overridepublic void showRole() {System.out.print("有钱人:");}@Overridepublic void shopping(ShopPlace shopPlace) {switch (shopPlace) {case food:System.out.println("鱼子酱配佛跳墙");break;case relax:System.out.println("私人SPA");break;case clothing:System.out.println("去Prada买衣服");break;}}}}enum ShopPlace {clothing,food,relax}}

上面代码存在以下问题:

1)所有业务都集中在一个类中,类功能繁多,违背单一原则。

2)条件判断语句过多。

3)如果新增一个角色或者店铺地区,那么将增加更多的条件判断语句。也违背了开闭原则。

1 访问者模式

访问者模式提供一个作用于某对象结构中的各元素的操作表示。它包含访问者(打工人、学生及有钱人)和被访问元素(服装区、饮食区及休闲区)两个主要组成部分。这些被访问的元素通常具有不同的类型,且不同的访问者对它们进行不同的访问操作。

图 访问者模式UML

Visitor,抽象访问者。为对象中每个具体元素类ConcreteElement声明一个访问操作,从这个操作的参数类型可以清楚知道访问的具体元素的类型。

ConcreteVisitor,具体访问者。实现了每个由抽象访问者声明的操作,每个操作用于访问对象结构中一种类型的元素。

Element,抽象元素。定义了一个accept方法,该方法通常以一个抽象访问者作为参数。

ConcreteElement,具体元素,实现了accept方法,在accept方法中调用访问者的访问方法以便完成对一个元素的操作。

ObjectStructure,对象结构是一个元素的集合,用于存放元素对象,并且提供了遍历其内部元素的方法。

public interface RoleVisitor {void visit(ClothingSpaceElement element);void visit(FoodSpaceElement element);void visit(RelaxSpaceElement element);}public interface SpaceElement {void accept(RoleVisitor visitor);}public class WorkVisitor implements RoleVisitor{@Overridepublic void visit(ClothingSpaceElement element) {System.out.println("打工人:去优衣库买件衣服");}@Overridepublic void visit(FoodSpaceElement element) {System.out.println("打工人:吃兰州拉面");}@Overridepublic void visit(RelaxSpaceElement element) {System.out.println("打工人:去看场电影");}}public class StudentVisitor implements RoleVisitor{@Overridepublic void visit(ClothingSpaceElement element) {System.out.println("学生:只逛逛");}@Overridepublic void visit(FoodSpaceElement element) {System.out.println("学生:吃麻辣烫");}@Overridepublic void visit(RelaxSpaceElement element) {System.out.println("学生:去游戏厅打游戏");}
}public class RicherManVisitor implements RoleVisitor{@Overridepublic void visit(ClothingSpaceElement element) {System.out.println("有钱人:买Prada的衣服");}@Overridepublic void visit(FoodSpaceElement element) {System.out.println("有钱人:吃鱼子酱配佛跳墙");}@Overridepublic void visit(RelaxSpaceElement element) {System.out.println("有钱人:私人SPA");}
}public class ClothingSpaceElement implements SpaceElement{@Overridepublic void accept(RoleVisitor visitor) {visitor.visit(this);}
}public class FoodSpaceElement implements SpaceElement{@Overridepublic void accept(RoleVisitor visitor) {visitor.visit(this);}
}public class RelaxSpaceElement implements SpaceElement{@Overridepublic void accept(RoleVisitor visitor) {visitor.visit(this);}
}

2 优缺点

优点:

1)增加新的访问操作很方便。只需要增加一个新的具体访问者类,实现简单,无须修改源代码,符合开闭原则。

2)将有关元素对象的访问行为集中到一个访问者对象中,而不是分散在一个个的元素类中,类的职责更加清晰,有利于对象结构中元素对象的复用,相同的对象结构可以供多个不同的访问者访问。

缺点:

1)增加新的元素类很困难,每增加一个新的元素类都意味着要在抽象访问者角色中增加一个新的抽象操作,并在每个具体访问者类中增加相应的具体操作,这违背了开闭原则。

2)破坏封装,访问者模式要求访问者对象访问并调用每一个元素对象的操作,这意味着元素对象有时候必须暴露一些自己的内部操作和内部状态。

3 适用场景

1)一个对象结构包含多种类型的对象,希望对这些对象实施一些依赖其具体类型的操作。

2)需要对一个对象结构中的对象进行很多不同且不相关的操作,而且需要避免让这些操作“污染”这些对象的类,也不需要在增加新操作时修改这些类。

3)对象结构中元素对象对应的类很少改变,但经常需要在此对象结构上定义新的操作。

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

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

相关文章

立创eda专业版学习笔记(8)(运行模式)

以前没注意过这个问题&#xff0c;我有2台电脑&#xff0c;都能登录eda专业版&#xff0c;但是一台是全在线模式&#xff0c;另外一台是半离线模式&#xff0c;虽然是同一个账号&#xff0c;但是打开里面的工程会发现&#xff0c;两边的工程完全不同&#xff0c;因为一台的工程…

【UE5 Cesium】actor随着视角远近来变化其本身大小

效果 步骤 1. 首先我将“DynamicPawn”设置为默认的pawn类 2. 新建一个父类为actor的蓝图&#xff0c;添加一个静态网格体组件 当事件开始运行后添加一个定时器&#xff0c;委托给一个自定义事件&#xff0c;每2s执行一次&#xff0c;该事件每2s获取一下“DynamicPawn”和acto…

kafka问题汇总

报错1&#xff1a; 解决方式 1、停止docker服务   输入如下命令停止docker服务 systemctl stop docker 或者service docker stop1   停止成功的话&#xff0c;再输入docker ps 就会提示出下边的话&#xff1a; Cannot connect to the Docker daemon. Is the docker daem…

YoloV5训练V3Det数据集实战

摘要 V3Det&#xff1a;一个庞大的词汇视觉检测数据集&#xff0c;在大量真实世界图像上具有精确注释的边界框&#xff0c;其包含13029个类别中的245k个图像&#xff08;比LVIS大10倍&#xff09;&#xff0c;数据集已经开源&#xff01; 图片的数量比COCO多一些&#xff0c;…

云计算的大模型之争,亚马逊云科技落后了?

文丨智能相对论 作者丨沈浪 “OpenAI使用了Azure的智能云服务”——在过去的半年&#xff0c;这几乎成为了微软智能云最好的广告词。 正所谓“水涨船高”&#xff0c;凭借OpenAI旗下的ChatGPT在全球范围内爆发&#xff0c;微软趁势拉了一波自家的云计算业务。2023年二季度&a…

嵌入式C语言自我修养《数据存储与指针》学习笔记

目录 一、数据类型和存储 1.大端模式和小端模式 2.有符号数和无符号数 二、数据对齐 1.为什么要数据对齐 2.结构体对齐 3.联合体对齐 三、数据的可移植性 四、 Linux内核中的size_t类型 五、typedef的使用 1. typedef的基本用法 2.使用typedef的优势 3. typedef的作用域 六…

【SQL篇】一、Flink动态表与流的关系以及DDL语法

文章目录 1、启动SQL客户端2、SQL客户端常用配置3、动态表和持续查询4、将流转为动态表5、用SQL持续查询6、动态表转为流7、时间属性8、DDL-数据库相关9、DDL-表相关 1、启动SQL客户端 启动Flink&#xff08;基于yarn-session模式为例&#xff09;&#xff1a; /opt/module/f…

Java_类和对象详解

文章目录 前言简单认识类类定义和使用类的实例化引用的一些注意事项 类和对象的说明及关系this引用为什么要有this引用this应用this特性 构造方法构造特性及应用用this简化用idea编译器快捷创建构造 封装封装的概念访问限定符 封装的扩展-包包的概念导入包中的类自定义包常见的…

Skywalking介绍

一个优秀的项目&#xff0c;除了具有高拓展的架构、高性能的方案、高质量的代码之外&#xff0c;还应该在上线后具备多角度的监控功能。现在企业中的监控服务也有很多&#xff0c;Skywalking除了提供多维度、多粒度的监控之外&#xff0c;也提供了良好的图形化界面以及性能剖析…

LeetCode 面试题 16.17. 连续数列

文章目录 一、题目二、C# 题解 一、题目 给定一个整数数组&#xff0c;找出总和最大的连续数列&#xff0c;并返回总和。 示例&#xff1a; 输入&#xff1a; [-2,1,-3,4,-1,2,1,-5,4] 输出&#xff1a; 6 解释&#xff1a; 连续子数组 [4,-1,2,1] 的和最大&#xff0c;为 6。…

DDD学习笔记

1)ddd&#xff1a; 软件复杂性的应对之道。 但是不是说&#xff1a;redis这种不会使用。 开发过程中&#xff0c;一直面临的一种复杂性。 是一种架构思想: 领域之间的组合。 让开发软件具有搭积木的感觉。 领域的核心是边界。 以领域划分为基础。 以通用语言为建设…

持续集成交付CICD:安装Jenkins Slave(从节点)

目录 一、实验 1.安装Jenkins Slave&#xff08;从节点&#xff09; 二、问题 1.salve节点启动jenkins报错 2.终止命令行后jenkins从节点状态不在线 一、实验 1.安装Jenkins Slave&#xff08;从节点&#xff09; &#xff08;1&#xff09;查看jenkins版本 Version 2.…

c语言进阶部分详解(《高质量C-C++编程》经典例题讲解及柔性数组)

上篇文章我介绍了介绍动态内存管理 的相关内容&#xff1a;c语言进阶部分详解&#xff08;详细解析动态内存管理&#xff09;-CSDN博客 各种源码大家可以去我的github主页进行查找&#xff1a;唔姆/比特学习过程2 (gitee.com) 今天便接“上回书所言”&#xff0c;来介绍《高质…

ElasticSearch 实现 全文检索 支持(PDF、TXT、Word、HTML等文件)通过 ingest-attachment 插件实现 文档的检索

一、Attachment 介绍 Attachment 插件是 Elasticsearch 中的一种插件&#xff0c;允许将各种二进制文件&#xff08;如PDF、Word文档等&#xff09;以及它们的内容索引到 Elasticsearch 中。插件使用 Apache Tika 库来解析和提取二进制文件的内容。通过使用 Attachment 插件&a…

Qt的事件

一、鼠标按下事件 //鼠标按下事件&#xff0c;获取屏幕位置&#xff0c;并显示&#xff0c;移动显示框 void Widget::mousePressEvent(QMouseEvent *event) {if(event->button() ! Qt::LeftButton){return ;}QPoint point event->pos();QPointF winPt event->…

Python学习-shutil模块和OS模块学习

shutil模块 针对文件的拷贝&#xff0c;删除&#xff0c;移动&#xff0c;压缩和解压操作 # 1.copyfileobj只能复制文件内容&#xff0c;无法复制权限#复制文件时&#xff0c;要选择自己有权限的目录执行操作&#xff0c;创建的文件会根据系统umask设定的参数来指定用户权限 s…

首发scitb包,一个为制作统计表格而生的R包

目前&#xff0c;本人写的第3个R包scitb包已经正式在R语言官方CRAN上线&#xff0c;scitb包是一个为生成专业化统计表格而生的R包。 可以使用以下代码安装 install.packages("scitb")scitb包对我而言是个很重要的R包&#xff0c;我的很多想法需要靠它做平台来实现&a…

项目实战:优化Servlet,把所有围绕Fruit操作的Servlet封装成一个Servlet

1、FruitServlet 这些Servlet都是围绕着Fruit进行的把所有对水果增删改查的Servlet放到一个Servlet里面&#xff0c;让tomcat实例化一个Servlet对象 package com.csdn.fruit.servlet; import com.csdn.fruit.dto.PageInfo; import com.csdn.fruit.dto.PageQueryParam; import c…

多级缓存之JVM进程缓存

1.什么是多级缓存 传统的缓存策略一般是请求到达Tomcat后&#xff0c;先查询Redis&#xff0c;如果未命中则查询数据库&#xff0c;如图&#xff1a; 存在下面的问题&#xff1a; 请求要经过Tomcat处理&#xff0c;Tomcat的性能成为整个系统的瓶颈 Redis缓存失效时&#xff0…

STM32笔记—DMA

目录 一、DMA简介 二、DMA主要特性 三、DMA框图 3.1 DMA处理 3.2 仲裁器 3.3 DMA通道 扩展: 断言&#xff1a; 枚举&#xff1a; 3.4 可编程的数据传输宽度、对齐方式和数据大小端 3.5 DMA请求映像 四、DMA基本结构 4.1 DMA_Init配置 4.2 实现DMAADC扫描模式 实现要求…