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

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

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 { // 打工人

            @Override
            public void showRole() {
                System.out.print("打工人:");
            }

            @Override
            public 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 { // 学生

            @Override
            public void showRole() {
                System.out.print("学生:");
            }

            @Override
            public 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 { // 有钱人

            @Override
            public void showRole() {
                System.out.print("有钱人:");
            }

            @Override
            public 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{

    @Override
    public void visit(ClothingSpaceElement element) {
        System.out.println("打工人:去优衣库买件衣服");
    }

    @Override
    public void visit(FoodSpaceElement element) {
        System.out.println("打工人:吃兰州拉面");
    }

    @Override
    public void visit(RelaxSpaceElement element) {
        System.out.println("打工人:去看场电影");
    }

}

public class StudentVisitor implements RoleVisitor{
    @Override
    public void visit(ClothingSpaceElement element) {
        System.out.println("学生:只逛逛");
    }

    @Override
    public void visit(FoodSpaceElement element) {
        System.out.println("学生:吃麻辣烫");
    }

    @Override
    public void visit(RelaxSpaceElement element) {
        System.out.println("学生:去游戏厅打游戏");
    }
}

public class RicherManVisitor implements RoleVisitor{
    @Override
    public void visit(ClothingSpaceElement element) {
        System.out.println("有钱人:买Prada的衣服");
    }

    @Override
    public void visit(FoodSpaceElement element) {
        System.out.println("有钱人:吃鱼子酱配佛跳墙");
    }

    @Override
    public void visit(RelaxSpaceElement element) {
        System.out.println("有钱人:私人SPA");
    }
}

public class ClothingSpaceElement implements SpaceElement{
    @Override
    public void accept(RoleVisitor visitor) {
        visitor.visit(this);
    }
}

public class FoodSpaceElement implements SpaceElement{
    @Override
    public void accept(RoleVisitor visitor) {
        visitor.visit(this);
    }
}

public class RelaxSpaceElement implements SpaceElement{
    @Override
    public void accept(RoleVisitor visitor) {
        visitor.visit(this);
    }
}

2 优缺点

优点:

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

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

缺点:

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

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

3 适用场景

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

拥抱中国发展新机遇,原知因制药再次亮相2023进博会

11月5日至10日&#xff0c;第六届进博会在国家会展中心&#xff08;上海&#xff09;成功举办。作为世界上首个以进口为主题的国家级博览会&#xff0c;进博会成为构建新发展格局的窗口、高水平开放的载体&#xff0c;持续为世界经济注入正能量。 原知因制药再次亮相进博会&am…

【C++】new和delete深度解析

文章目录 一、new/delete是什么&#xff1f;1.new2.delete 二、new/delete怎么用&#xff1f;1.new2.delete3.new[]4.[]delete 三、new/delete为什么&#xff1f;1.为什么有operator new/operator delete?2.为什么要匹配使用new和delete? new/delete测试环境&#xff1a;visu…

力扣21:合并两个有序链表

力扣21&#xff1a;合并两个有序链表 **题目描述&#xff1a;**将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4] 示例 2&…

超级APP,All in one APP

在信息化时代&#xff0c;企业需要处理的数据和使用的各种系统繁多复杂。然而&#xff0c;传统的应用往往孤立存在&#xff0c;导致数据无法流动和系统无法高效对接。WorkPlus作为一款超级APP&#xff0c;以其全面的功能和强大的集成能力&#xff0c;实现了数据到系统的全方位集…

高压MOS/低压MOS在单相离线式不间断电源上的应用-REASUNOS瑞森半导体

一、前言 单相离线式不间断电源只是备援性质的UPS&#xff0c;市电直接供电给用电设备再为电池充电&#xff0c;一旦市电供电品质不稳或停电时&#xff0c;市电的回路会自动切断&#xff0c;电池的直流电会被转换成交流电接手供电的任务&#xff0c;直到市电恢复正常。UPS只有…

Jmeter工具二次开发

一、JMeter 二次开发方向 1、函数开发&#xff0c;主要为JMeter 函数库 2、插件开发&#xff0c;一般主要做取样器开发 3、基于执行引擎开发&#xff0c;有效解决单独开发的测试平台或工具中&#xff0c;底层执行引擎开发相对复杂、周期长的问题&#xff0c;利用 JMeter 执行…

Redis为什么要使用SDS作为基本数据结构

Redis为什么要使用SDS作为基本数据结构 Redis SDS与C语言中字符串的对比二进制安全兼容部分C字符串函数 Redis SDS与C语言中字符串的对比 SDS中保存了字符串的长度属性&#xff0c;我们在获取字符串长度是的时间复杂度为O(1)&#xff0c;而C中字符串则需要对字符串进行遍历时间…

linux 不同用户不同jdk

0、 解压一个新版本的jdk 1、 检查root用户下的环境变量&#xff0c;是否配置了JAVA_HOME&#xff0c;基于这个变量再配置的PATH变量是实现切换的前提。 2、 创建新用户 adduser jdk11 passwd jfjfjfjfjfjfj123 3、 编辑改用下的 .bashrc 文件 执行命令进行编辑&#xff0…

倍福CX9020 Windows CE6.0安装中文字库方法(附字库文件)

应用背景介绍 倍福的EPC产品有些是附带Windows CE系统的&#xff0c;例如CX9020&#xff0c;而且多数系统都是英文的&#xff0c;而且没有附带中文的字库&#xff0c;如果想要在PLC HMI中使用中文进行显示就无法实现&#xff0c;经常有工程师在电脑上编好程序和界面以后测试没…

使用Navicat导出ER图详细教程

文章目录 打开Navicat&#xff0c;点击模型点击新建模型选择物理模型点击文件&#xff0c;选择从数据库导入选择要导入的数据库点击文件&#xff0c;选择导出的格式成品 打开Navicat&#xff0c;点击模型 点击新建模型 选择物理模型 点击文件&#xff0c;选择从数据库导入 选择…

C++动态库

C动态库 动态库文件&#xff08;Dynamic Link Library&#xff0c;DLL&#xff09;是程序在运行时所需要调用的库。静态库文件是程序在编译时所需要调用的库。 1 环境介绍 VS版本&#xff1a;VS2017 编程语言&#xff1a;C 2 功能介绍 使用VS2017项目模板创建C动态库生成…

Java程序设计实验5 | Java API应用

*本文是博主对Java各种实验的再整理与详解&#xff0c;除了代码部分和解析部分&#xff0c;一些题目还增加了拓展部分&#xff08;⭐&#xff09;。拓展部分不是实验报告中原有的内容&#xff0c;而是博主本人自己的补充&#xff0c;以方便大家额外学习、参考。 &#xff08;解…

CSS3 2D、3D转换

一、CSS3 2D转换&#xff1a; CSS3转换可以对元素进行移动、缩放、转动、拉长或拉伸。 2D变换的方法&#xff1a;translate()、rolate()、scale()、skew()、matrix()。 <style> div { width:200px; height:100px; background-color:red; /* Rotate div */ tran…

混淆矩阵和相应参数详解

如果一个模型在能够尽量捕获少数类的情况下&#xff0c;还能够尽量对多数类判断正确&#xff0c;则这个模型就非常优秀了。为了评估这样的能力&#xff0c;我们将引入新的模型评估指标&#xff1a;混淆矩阵和ROC曲线。 上面是混淆矩阵。接下来我们结合图像解释一下准确率&#…

AMESim 2021安装教程

主要是AMESim的安装 写在前面&#xff0c;由于项目需要&#xff0c;需要自学AMESim&#xff0c;因此需要安装这个软件&#xff0c;目前仅仅安装使用&#xff0c;还不涉及到与MATLAB的联合仿真&#xff0c;老板说用 RT LAB半实物仿真平台&#xff0c;但是简单搜了一下&#xff0…

阻塞队列和定时器的使用

阻塞队列 谈到队列,大家就能想到队列的先进先出原则,但有些特殊的队列,虽然也是先进先出的,但是带有阻塞功能,我们把这种队列叫做阻塞队列. ★如果队列为空,执行出队操作就会阻塞,阻塞到另外一个线程往队列里添加元素(队列不为空)为止. ★如果队列满了,执行入队操作时,也会阻…

“GUI图形化界面的魅力、SSH协议的安全通信与IDEA集成Git的高效开发“

文章目录 引言一、GUI图形化界面的实际应用二、SSH协议的安全通信什么是SSH?git/github生成密钥并通过远程github仓库配置 三、IDEA集成Git的快速上手指南总结 引言 在计算机科学领域&#xff0c;图形用户界面&#xff08;GUI&#xff09;是一种以图形方式呈现信息和交互的用…

Flutter笔记:绘图示例 - 一个简单的(Canvas )时钟应用

Flutter笔记 绘图示例 - 一个简单的&#xff08;Canvas &#xff09;时钟应用 作者&#xff1a;李俊才 &#xff08;jcLee95&#xff09;&#xff1a;https://blog.csdn.net/qq_28550263 邮箱 &#xff1a;291148484163.com 本文地址&#xff1a;https://blog.csdn.net/qq_2855…

大数据毕业设计选题推荐-污水处理大数据平台-Hadoop-Spark-Hive

✨作者主页&#xff1a;IT研究室✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Python…

【数据结构】Lambda

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