Java设计模式之行为型-访问者模式(UML类图+案例分析)

news2024/9/22 4:15:03

目录

一、基础概念

二、UML类图

三、角色设计

四、案例分析

五、总结


一、基础概念

访问者模式是一种对象行为型设计模式,它能够在不修改已有对象结构的前提下,为对象结构中的每个对象提供新的操作。

访问者模式的主要作用是把对元素对象的操作抽象出来封装到访问者类中,这样就可以对存在不同操作的元素对象进行统一的处理。

二、UML类图

三、角色设计

角色描述
抽象访问者角色定义访问元素对象的操作,每个操作对应一个方法
具体访问者角色实现访问者接口,给出对每个元素类型访问的具体实现
抽象元素角色定义一个含有接受操作方法accept()的接口,accept()方法以一个访问者对象为参数
具体元素角色实现抽象元素接口,每个具体元素都要实现accept()方法,在accept()方法中调用访问者对象的对应方法
对象结构角色可以枚举它的元素,可以提供高层的接口以允许访问者访问它的元素

四、案例分析

下面通过一段代码演示如何使用访问者模式来对不同类型的资源文件(Image、Video、Document)进行压缩操作。

客户端可以为ResourceFileStructure添加不同的资源文件,然后传入一个Compressor访问者对象,就可以通过统一的访问接口对不同资源文件进行压缩操作,而不需要修改资源文件类的代码。

定义Compressor接口(抽象访问者角色),声明了压缩每一种资源文件的方法 :

public interface Compressor {

    void compress(Image image);
    void compress(Video video);
    void compress(Document document);

}

ZipCompressor类(具体访问者角色),实现了压缩每一种资源文件的具体操作:

public class ZipCompressor implements Compressor {

    @Override
    public void compress(Image image) {
        System.out.println("压缩了图片:"+image.getName());
    }

    @Override
    public void compress(Video video) {
        System.out.println("压缩了视频:"+video.getName());
    }

    @Override
    public void compress(Document document) {
        System.out.println("压缩了文档:"+document.getName());
    }

}

 ResourceFile接口(抽象元素角色),声明了接受访问者的accept方法:

public interface ResourceFile {

  void accept(Compressor compressor);

}

Image、Video、Document类(具体元素角色),提供了资源文件信息,并在accept方法中调用访问者的对应方法:

public class Image implements ResourceFile {

  private String name;
  public Image(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

  @Override
  public void accept(Compressor compressor) {
    compressor.compress(this);
  }

}

public class Video implements ResourceFile {

  private String name;
  public Video(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

  @Override
  public void accept(Compressor compressor) {
    compressor.compress(this);
  }

}

public class Document implements ResourceFile {

  private String name;
  public Document(String name) {
    this.name = name;
  }

  public String getName() {
    return name;
  }

  @Override
  public void accept(Compressor compressor) {
    compressor.compress(this);
  }

}

ResourceFileStructure类(对象结构角色)管理所有元素,并可以遍历元素使其接受访问者访问:

import java.util.ArrayList;
import java.util.List;

public class ResourceFileStructure {

  private List<ResourceFile> files = new ArrayList<>();

  public void addResource(ResourceFile file) {
    files.add(file);
  }

  public void handleVisiting(Compressor compressor) {
    for(ResourceFile file : files) {
      // 调用元素的accept方法
      file.accept(compressor);
    }
  }
}

客户端:

public class Client {

    public static void main(String[] args) {
        // 客户端代码
        ResourceFileStructure structure = new ResourceFileStructure();

        // 添加资源文件
        structure.addResource(new Image("a.png"));
        structure.addResource(new Video("b.mp4"));
        structure.addResource(new Document("c.doc"));

        Compressor compressor = new ZipCompressor();

        // 处理访问
        structure.handleVisiting(compressor);

        // 输出结果
        System.out.println("文件压缩完成");
    }
}

运行结果如下:

该案例的执行流程是:

1、创建资源文件对象(Image、Video、Document等)和资源文件结构ResourceFileStructure对象。

2、向ResourceFileStructure对象中添加资源文件对象。

3、创建具体访问者对象,例如ZipCompressor。

4、调用ResourceFileStructure的handleVisiting()方法,传入访问者对象。

5、在handleVisiting()方法中遍历内部存储的所有资源文件,并调用每个资源文件的accept()方法,以访问者对象作为参数。

6、在每个资源文件类的accept()方法中,调用访问者对象的参数对应的方法,例如调用compressor.compress(this)。

7、于是压缩程序类中的compress()方法就会被执行,从而实现对该资源文件的压缩操作。

8、这样就通过访问者对象使不同类型的资源文件进行了统一的压缩处理,而不需要修改资源文件类的代码。

9、如果需要新增一种压缩方式,只需要新增一个实现Compressor接口的类,不需要修改资源文件类。 

五、总结

优点:

1、增加新的操作很容易。访问者模式使得新增操作变得很容易。如果需要增加新的操作,只需要添加一个新的具体访问者类即可,无需作用于其他类的修改。

2、实现了数据结构与操作分离。访问者模式将数据结构与作用于结构上的操作分离开来,使得操作集合可相对自由地演化而不影响系统的数据结构。

3、符合单一职责原则。访问者模式把相关的行为封装到一个访问者对象中,使每个访问者的功能都比较单一。

4、扩展性良好。可以在不修改对象结构中的元素的情况下,为对象结构中的元素添加新的功能。

缺点:

1、具体元素对访问者公布细节。访问者模式中具体元素对访问者公布自己的细节,这打破了对象的封装性。

2、具体元素变更困难。如果一个对象结构中的具体元素发生变化,例如新增或者删除了元素,那么访问者都需要进行适当的修改。

3、违反了依赖倒置原则。访问者依赖了具体元素,而不是抽象元素。

4、破坏对象结构的封装。访问者模式中对象结构必须公布自身的内部细节,否则访问者无法访问对象内部的元素,这破坏了对象的封装性。

应用场景:

1、对象结构稳定,但其操作经常变化的系统。访问者模式可以隔离变化的部分。

2、需要对对象结构的对象执行很多不同和不相关的操作,可以将这些操作集中到访问者中,避免污染对象类。

3、希望新增操作时不改变对象结构,新增访问者可以实现此需求。

4、需要对不同对象结构执行共同操作,可以使用访问者模式重用操作。

5、对象结构中对象类型经常改变,访问者模式可以隔离这种变化对对象结构的影响。

6、在不改变对象类的情况下,为对象增加新功能。

7、将相关操作集中到访问者中,避免将操作分散到对象类中。

8、将变化点从稳定的对象结构中抽象出来,提高软件灵活性。

符合的设计原则:

1、单一职责原则(Single Responsibility Principle)

访问者模式通过将相关行为抽取到访问者类中,使每个访问者类都只负责一组特定的行为,这点符合单一职责原则。

访问者模式适用于数据结构相对稳定,但经常需要在此数据结构上定义新的操作的时候使用。如果数据结构经常变化,或者都操作不太发生变化,则不太适合使用访问者模式。

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

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

相关文章

进程通信与信号

1.管道 匿名管道&#xff1a;匿名管道用于进程间通信&#xff0c;且仅限于本地父子进程之间的通信 管道符号 | 进程间通信的本质就是&#xff0c;让不同的进程看到同一份资源&#xff0c;使用匿名管道实现父子进程间通信的原理就是&#xff0c;让两个父子进程先看到同一份被打…

【云原生】Docker跨主机网络Overlay与Macvlan的区别

跨主机网络通信解决方案 docker原生的overlay和macvlan 第三方的flannel&#xff0c;weave&#xff0c;calico 1.overlay网络 在Docker中&#xff0c;Overlay网络是一种容器网络驱动程序&#xff0c;它允许在多个Docker主机上创建一个虚拟网络&#xff0c;使得容器可以通过这…

Python 最优传输工具箱(Python Optimal Transport)

最近在研究最优传输的相关理论&#xff0c;博主使用的是python编程语言&#xff0c;在这里给大家推荐一个Python最优传输工具箱&#xff1a;Python Optimal Transport&#xff08;pot)与geomloss 其中geomloss是针对pytorch张量的&#xff0c;ot是针对numpy数组的&#xff1b;g…

装饰器模式揭秘:我用装饰器给手机集成了ChatGPT

在平时的开发过程中&#xff0c;我们经常会遇到需要给一个类增加额外功能的需求&#xff0c;但又不想破坏类的原有结构。这时候&#xff0c;装饰器模式就能大显神威了&#xff01;接下来&#xff0c;我将带你深入了解装饰器模式的原理、优缺点、适用场景以及如何在实际开发中巧…

无法找到docker.sock

os环境&#xff1a;麒麟v10(申威) 问题描述&#xff1a; systemctl start docker 然后无法使用docker [rootnode2 ~]# systemctl restart docker [rootnode2 ~]# docker ps Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon r…

4、应用层https27

https协议加密流程&#xff1a;使用ssl加密。 一、HTTPS协议 对HTTP协议进行加密后的一个新的协议。 1、加密概念 单说数据加密过去狭义&#xff0c;更多的是防止数据被监听劫持。 加密包含俩个方面&#xff1a;身份验证&#xff0c;加密传输。 1.1身份验证 验证对端的身…

四、传播

文章目录 1、草药迷阵问题2、时序回溯搜索3、传播搜索THE END 1、草药迷阵问题 \qquad 有一个10*10的百草药柜&#xff0c;每一个抽屉里都有5种不同属性的草药&#xff0c;依次打开抽屉来长出草药迷阵&#xff0c;要求寻找一种神奇的药方&#xff0c;满足&#xff1a; 横行&am…

数据结构——C++无锁队列

数据结构——C无锁队列 贺志国 2023.7.11 上一篇博客给出了最简单的C数据结构——堆栈的几种无锁实现方法。队列的挑战与栈的有些不同&#xff0c;因为Push()和Pop()函数在队列中操作的不是同一个地方。因此同步的需求就不一样。需要保证对一端的修改是正确的&#xff0c;且对…

(中等)LeetCode 3. 无重复字符到的最长子串 Java

滑动窗口 以示例一为例&#xff0c;找出从每一个字符开始的&#xff0c;不包含重复字符的最长子串&#xff0c;那么&#xff0c;其中最长的那个字符串即为答案。 当我们一次递增地枚举子串的起始位置&#xff0c;会发现子串的结束位置也是递增的&#xff0c;原因在于&#xf…

Django项目创建

Django项目创建 文章目录 Django项目创建&#x1f468;‍&#x1f3eb;方式一&#xff1a;终端命令行方式&#x1f468;‍&#x1f52c;方式二&#xff1a;Pycharm创建 &#x1f468;‍&#x1f3eb;方式一&#xff1a;终端命令行方式 1️⃣cmd打开终端&#xff0c;切换到指定目…

WebSell管理工具--中国蚁剑安装教程以及初始化

简介&#xff1a;中国蚁剑是一款开源的跨平台WebShell网站管理工具 蚁剑的下载安装&#xff1a; GitHub项目地址&#xff1a;https://github.com/AntSwordProject/ Windows下载安装&#xff1a; 百度网盘下载链接&#xff1a;链接&#xff1a;https://pan.baidu.com/s/1A5wK…

超细整理,性能测试-性能指标监控命令详细实战,一篇速通

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能监控命令&…

自动驾驶代客泊车AVP摄像头与ECU交互需求规范

目录 1 文档范围及控制方法... 5 1.1 目的.... 5 1.2 文档授权... 5 1.3 文档变更管理... 5 1.4 缩写.... 5 1.5 术语.... 5 2 系统组成... 6 2.1 系统框图... 6 2.2 电源供应和时序要求... 7 2.2.1 摄像头供电控制... 7 2.2.2 摄像头上电时序要求…

论文(3)——使用ChatGPT快速提高科研能力!!如何快速构建代码?怎么提高自己的科研能力?如何提高自己的生产力?

文章目录 引言问题描述问题解决智能开发软件的方法ChatGPT Plus 代码解释器使用ChatGPT插件功能 代码工具Coplit学生优惠免费申请Coplit和pycharm的结合 NewBing的申请 总结参考引用 引言 chatGPT大模型用于问问题和debug&#xff0c;NewBing用于搜索论文&#xff0c;cpolit用…

简述HashMap的扩容机制

注意&#xff1a;本博客需要对HashMap源码有过一定理解&#xff0c;看过源码比较好&#xff0c;仅供互相学习参考 JDK1.7和JDK1.8对比 1.7版本&#xff1a; (1). 首先生成一个新数组(2). 遍历老数组每个位置中的链表元素(3). 取每个元素的key&#xff0c;重新计算每个元素在…

深度学习ai学习方向如何规划,算法竞赛,机器学习,搭建环境等答疑

目录 1了解人工智能的背景知识 2 补充数学或编程知识 3 熟悉机器学习工具库 4 系统的学习人工智能 5 动手去做一些AI应用 1了解人工智能的背景知识 一些虽然存在但是在研究或者工业上不常用的知识&#xff0c;为自己腾出更多的时间来去学习&#xff0c;研究。 人工智能里…

2023.7.16-约数的枚举

功能&#xff1a;输入一个整数&#xff0c;结果打印出这个整数所有的约数。 程序&#xff1a; #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> int main() {int a0, b;printf("请输入一个整数&#xff1a;");scanf("%d",&a);printf(&qu…

迭代器模式:相比直接遍历集合数据,使用迭代器有哪些优势?

今天&#xff0c;我们学习另外一种行为型设计模式&#xff0c;迭代器模式。它用来遍历集合对象。不过&#xff0c;很多编程语言都将迭代器作为一个基础的类库&#xff0c;直接提供出来了。在平时开发中&#xff0c;特别是业务开发&#xff0c;我们直接使用即可&#xff0c;很少…

前端基础:HTML和CSS简介

目录 1、HTML 简介 &#xff08;1&#xff09;在 HTML 中引入外部 CSS &#xff08;2&#xff09;在 HTML 中引入外部 JavaScript 2、CSS 简介 &#xff08;1&#xff09;CSS 的基本语法 &#xff08;2&#xff09;三种使用 CSS 的方法 2.1 - 外部 CSS 的使用 2.2 - 内…

Redis简介与安装

文章目录 前言一、Redis简介1. Redis是什么2. Redis的特点3. 数据库类型4. Redis 应用场景 二、Redis下载与安装1. Redis安装包下载地址2. 在 windows系统安装 Redis3. 在Linux系统安装Redis 总结 前言 为了巩固所学的知识&#xff0c;作者尝试着开始发布一些学习笔记类的博客…