设计模式-访问者模式

news2024/11/26 14:41:48

访问者模式

  • 问题背景
    • 解决方案:传统方案
  • 访问者模式
    • 基本介绍
    • 原理UML类图
  • 使用访问者模式解决问题
    • UML类图
    • 示例代码
    • 运行结果
  • 注意事项和细节

问题背景

我们来制作一台电脑,他的硬件有CPU和磁盘,CPU和磁盘类都有一个常量作为他们各自的数据,软件有操作系统来操作CPU和磁盘的常量值,不同的系统可以给CPU和磁盘写入不同的值,要求是不变CPU和磁盘的情况下可以动态升级系统。

解决方案:传统方案

传统方案就是我们直接写两个类CPU和Disk类,然后写一个操作系统类去聚合CPU类和Disk类,这样操作系统就可以操作了。

缺点:
耦合性太强,后期如果要升级系统,我们就要重新那一个cpu和磁盘和新的系统来组成一台电脑。这是不现实的,我们应该是CPU和磁盘不动的情况下动态升级系统。

访问者模式

基本介绍

1)访问者模式:在结构不变的情况下,可以动态改变内部元素的动作。例如上面的问题,结构不变的情况下,我们可以动态升级操作系统
2)主要将数据结构和数据操作分离,解决数据结构和操作耦合性问题。
3)访问者模式的基本工作原理是:在被访问的类里面加一个对外提供的接受访问者的类,然后被访问这将自己交给访问者类,这样访问者类就可以控制被访问者类
4)访问者模式主要应用场景:需要对一个对象结构中的对象进行很多不同操作 (这些操作彼此没有关联),同时需要避免让这些操作“污染”这些对象的类,可以选用访问者模式解决

原理UML类图

在这里插入图片描述
1)Element是被访问者接口,他提供一个方法accept来接收一个访问者对象来将自己传给访问者。
2)Visitor是访问者接口,访问者定义了操作被访问者数据的逻辑
3)ObjectStruture类用来存储被访问者
4)如果不明白可以对照下面真实实例的类图来理解

使用访问者模式解决问题

UML类图

在这里插入图片描述
1)Hardware是硬件接口,是被访问者,电脑的硬件CpuHardware和DiskHardware 都要继承这个接口
2)OperatingSystemVisitor是操作系统接口,是访问者,不同版本的操作系统都要继承这个接口
3)Computer是电脑类,它聚合了硬件CPU和Disk,通过传入的操作系统visitor类操作CPU和Disk

示例代码

/**
 * 硬件设施接口
 * @author wenqiang
 * @date 2023/6/1
 */
public interface Hardware {

    /**
     * 所有的硬件都可以被访问者访问
     *
     * @param visitor
     */
    void accept(OperatingSystemVisitor visitor);
}

/**
 * CPU
 *
 * @author wenqiang
 * @date 2023/6/1
 */
public class CpuHardware implements Hardware{

    private String commond;

    public String getCommond() {
        return commond;
    }

    public void setCommond(String commond) {
        this.commond = commond;
    }

    @Override
    public void accept(OperatingSystemVisitor visitor) {
        visitor.operateCpu(this);
    }
}
/**
 * 磁盘
 *
 * @author wenqiang
 * @date 2023/6/1
 */
public class DiskHardware implements Hardware{

    private String commond;

    public String getCommond() {
        return commond;
    }

    public void setCommond(String commond) {
        this.commond = commond;
    }

    @Override
    public void accept(OperatingSystemVisitor visitor) {
        visitor.operateDisk(this);
    }
}
/**
 * 访问者 操作系统
 *
 * @author wenqiang
 * @date 2023/6/1
 */
public interface OperatingSystemVisitor {
    /**
     * 访问者操作CPU
     *
     * @param cpu
     */
    void operateCpu(CpuHardware cpu);

    /**
     * 访问者操作Disk
     *
     * @param disk
     */
    void operateDisk(DiskHardware disk);
}
/**
 * 电脑
 * 
 * @author wenqiang
 * @date 2023/6/1
 */
public class Computer {

    private CpuHardware cpu;

    private DiskHardware disk;

    private OperatingSystemVisitor visitor;

    public Computer(OperatingSystemVisitor visitor) {
        cpu = new CpuHardware();
        disk = new DiskHardware();
        this.visitor = visitor;
    }

    public void printCpu() {
        cpu.accept(visitor);
        System.out.println("CPU输出:" + cpu.getCommond());
    }

    public void printDisk() {
        disk.accept(visitor);
        System.out.println("磁盘输出:" + disk.getCommond());
    }
}

第一个版本的操作系统我们写“1+1=1”,写错了指令,我们升级版本来更新这个指令,所以版本二变为了写“1+1=2”

/**
 * 访问者 操作系统版本1
 * 
 * @author wenqiang
 * @date 2023/6/1
 */
public class OperatingSystemVersion_1 implements OperatingSystemVisitor{

    @Override
    public void operateCpu(CpuHardware cpu) {
        cpu.setCommond("运算1+1=1");
    }

    @Override
    public void operateDisk(DiskHardware disk) {
        disk.setCommond("记住1+1=1");
    }
}
/**
 * 操作系统版本2
 * 
 * @author wenqiang
 * @date 2023/6/1
 */
public class OperatingSystemVersion_2 implements OperatingSystemVisitor{


    @Override
    public void operateCpu(CpuHardware cpu) {
        cpu.setCommond("运算1+1=2");
    }

    @Override
    public void operateDisk(DiskHardware disk) {
        disk.setCommond("记住1+1=2");
    }
}

使用者

/**
 * 使用者
 *
 * @author wenqiang
 * @date 2023/6/1
 */
public class Client {
    public static void main(String[] args) {
        OperatingSystemVisitor visitor_1 = new OperatingSystemVersion_1();
        Computer computer_1 = new Computer(visitor_1);
        computer_1.printCpu();
        computer_1.printDisk();

        // 我们发现系统编写错误了,升级系统
        OperatingSystemVisitor visitor_2 = new OperatingSystemVersion_2();
        Computer computer_2 = new Computer(visitor_2);
        computer_2.printCpu();
        computer_2.printDisk();
    }
}

运行结果

在这里插入图片描述

注意事项和细节

优点
1)访问者模式符合单一职责原则、让程序具有优秀的扩展性、灵活性非常高
2)访问者模式可以对功能进行统一,可以做报表、UI、拦截器与过滤器,适用于数据结构相对稳定的系统

缺点
1)具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的,这样造成了具体元素变更比较困难
2)违背了依赖倒转原则。访问者依赖的是具体元素,而不是抽象元素
3)因此,如果一个系统有比较稳定的数据结构,又有经常变化的功能需求,那么访问者模式就是比较合适的.

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java企业级信息系统开发学习笔记10 利用MyBatis实现关联查询

文章目录 一、学习目标(一)针对三张表关联查询(二)按班级编号查询班级信息(三)查询全部班级信息 二、创建数据库(一)创建教师表(二)创建班级表(三…

Linux系统搭建Java的运行环境

目录 JDKTomcatMySQL JDK 对于Linux安装JDK有很多方法~ 这里就掌握最简单的办法—基于yum来进行安装~ yum是“包管理器”,相当于应用商店~ 首先,先搜索一下,看看yum上关于jdk有没有,以及叫啥名字~ 通过 yum list命令&#xff0…

六一亲子嘉年华 | 来迅镭激光过一个五彩缤纷的儿童节!

童年是梦,如七彩的画卷; 童年是诗,如璀璨的星空; 童年是歌,如跳跃的音符! 在“六一”儿童节到来之际 为给员工及子女创造一个难忘的亲子时光 迅镭激光开展了六一亲子嘉年华主题活动 让孩子们在迅镭大家庭的…

Minigpt4实战搭建

简介 Minigpt4虽然放出了网页版但是使用后发现网页体验的话,由于并发量比较大,很容易突然卡顿的现象,所以下面我主要讲解一下如何进行本地部署。 之前文章已经介绍过Minigpt4了这里就不重复赘述了,不了解的可以去看看https://bl…

使用python开发“魂斗罗”游戏

使用python开发“魂斗罗”游戏 开发完整的魂斗罗(Contra)游戏是一个庞大的任务,它涉及到图形渲染、物理碰撞、敌人AI、游戏关卡等多个方面。在这个简短的交互中,我将向你展示一个基本的魂斗罗风格的游戏框架,你可以在此…

结构化文档发布的故事和性能调优

前阵子一个TW朋友跟我抱怨他们的文档发布很慢。正常发布需要一个晚上才能完成发布。中间如果出点错,就得重新发布,那么中间是漫长的等待。 不像MS Word或者InDesign这样所见即所得的软件,结构化文档源文件是XML格式的,就像计算机…

C语言——数据在内存中的存储(下)

数据在内存中的存储(下) 1. 浮点数在内存中的存储 浮点数家族: float double long double 浮点数的表示范围: 这里要引用float.h头文件 【实例一】 //输出结果是什么? int main() {int n 9;float *pFloat (float…

【代码规范】Google开源项目风格指南

系列综述: 💞目的:本系列是个人整理为了秋招面试的,整理期间苛求每个知识点,平衡理解简易度与深入程度。 🥰来源:材料主要源于Google开源项目风格指南进行的,每个知识点的修正和深入…

基于卡尔曼滤波实现线性目标跟踪

文章目录 前言卡尔曼滤波基本推导运算 实现目标检测卡尔曼预测器ID分配器(跟踪器) 完整代码代码总结 前言 一个需求,在一个稳定的场景当中,实现目标检测计数算法。 任务点: 实现目标检测完成对不同类别的物品进行计数…

Three.js--》实现3d字体模型展示

目录 项目搭建 初始化three.js基础代码 设置环境纹理 加载字体模型 今天简单实现一个three.js的小Demo,加强自己对three知识的掌握与学习,只有在项目中才能灵活将所学知识运用起来,话不多说直接开始。 项目搭建 本案例还是借助框架书写…

前后端交互模型http协议Ajax简介

0、前言:本文只是对“前后端交互模型&http协议&Ajax简介”当中的理论,作用,方法进行总结说明,用于回顾知识,做概括总结,没有具体实现代码。 1、前后端交互模型: 前端发送请求&#xff…

信号机制上(信号概念、发送、定时器、信号捕捉、SIGCHLD)

一、信号机制 概念:信号是在软件层次上对中断机制的一种模拟,是一种异步通信方式 所有信号的产生及处理全部都是由内核完成的 信号的产生: 1 按键产生 2 系统调用函数产生(比如raise, kill) 3 硬件异…

连接MQTT服务端

MQTT客户端之间要想实现通讯,必须要通过MQTT服务端。因此MQTT客户端无论是发布消息还是订阅消息,首先都要连接MQTT服务端。 MQTT客户端连接服务端一共有两步。 第一步(CONNECT请求) 首先MQTT客户端将会向服务端发送连接请求。该…

HBase 的关键流程解析

前言 本文隶属于专栏《大数据技术体系》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢! 本专栏目录结构和参考文献请见大数据技术体系 正文 HBase 客户端会将查询过的 HRegion 的位置信息…

【Python爬虫】采集电商商品评价信息

目录 一、数据采集逻辑二、数据Schema三、数据爬取1.导入库2.对爬虫程序进行伪装3.抓取商品评论信息4.防止反爬,每爬取一页数据后,设置程序休眠环节 四、数据存储1. 存储到csv 2.存储到数据库 一、数据采集逻辑 在进行数据采集之前,明确哪些…

Linux下C语言文件描述符操作(dup / dup2 / sendfile / splice / tee)

Linux的哲学是一切皆文件&#xff0c;而操作文件是通过文件描述符来进行。本文梳理一下dup / dup2 / sendfile / splice/ tee函数对文件描述符的操作。 目录 1.dup 2.dup2 3.sendfile 4.splice 5.tee 1.dup #include <unistd.h> int dup(int fd); 复制一个现有的…

Java基础(maven)——maven新建项目 常用IO工具 Durid数据库工具 案例

目录 引出用Maven建项目0.Maven配置方式1.io流的工具IOUtils/FileUtils1&#xff09;可以读文件、按照行读、读网页等&#xff1b;2&#xff09;配合hasmap进行简体繁体转换 2.durid数据库连接工具1&#xff09;创建连接&#xff0c;durid进行连接管理2&#xff09;查询的方式q…

chatgpt赋能python:Python中的转置函数-一种简单而高效的矩阵操作

Python中的转置函数 - 一种简单而高效的矩阵操作 作为一名10年的Python编程经验工程师&#xff0c;掌握利用Python进行矩阵操作是必不可少的。Python中提供了各种高效的矩阵操作功能&#xff0c;其中之一就是转置函数。 什么是转置&#xff1f; 在数学中&#xff0c;矩阵转置…

追寻幸福:探索幸福的关键特征和行为

目录 1. 积极的心态 2. 良好的人际关系 3. 自我接纳和自尊 4. 追求意义和目标 5. 健康的身心状态 6. 感知和实现个人价值 幸福是一个主观的感受&#xff0c;因此不同的人对于幸福的定义和追求方式可能会有所不同。然而&#xff0c;有一些共同的特点和行为模式&#xff0c…

【数据结构】难度上一个台阶的二叉树实现

【数据结构】难度上一个台阶的二叉树实现 一、什么是树和二叉树&#xff1f;二、目标三、实现3.1、初始化工作3.2、二叉树的前序遍历3.2.1、原理图解3.2.2、代码实现 3.3、二叉树的创建3.3.1、原理解析3.3.2、代码实现 3.4、二叉树的中序遍历3.5、二叉树的后序遍历3.6、二叉树的…