设计模式之访问者模式:灵活访问对象结构的强大工具

news2024/9/21 20:36:18

访问者模式

访问者模式(Visitor Pattern)是一种行为型设计模式,允许在不改变数据结构的前提下定义在这些结构上的新操作。它将操作行为与对象结构分离,使得可以在不修改对象结构的情况下添加新的操作行为。

访问者模式的应用场景

当需要对一个复杂的对象结构(如集合、树形结构)进行不同的操作,但又不希望因为添加新操作而频繁修改数据结构时,可以使用访问者模式。

访问者模式的原理及 UML 类图

访问者模式核心思想:将操作行为封装在访问者中,而将对象结构视为可被访问的元素。每个元素实现一个 accept() 方法,让访问者通过这个方法对元素进行操作。

  • Element(元素接口):定义了接受访问者的方法 accept(),让访问者可以对该元素进行操作。
  • ConcreteElementA 和 ConcreteElementB(具体元素类):具体的元素类实现了 accept() 方法,在方法中调用了访问者的 visit() 方法。
  • Visitor(访问者接口):定义了访问不同类型元素的操作方法,如 visitConcreteElementA()visitConcreteElementB()
  • ConcreteVisitor1 和 ConcreteVisitor2(具体访问者类):实现访问者接口,提供了对不同元素的具体操作。
  • ObjectStructure(对象结构):包含一个或多个元素(Element),它可以遍历这些元素并让访问者依次访问它们。accept() 方法会遍历所有元素,并让每个元素接受访问者。

在这里插入图片描述

生动案例举例:电子设备的维护系统

假设我们有一个 电子设备维护系统,其中包含不同类型的设备(如电脑、手机等)。每种设备需要定期进行不同的维护任务,如软件更新、硬件检查。使用访问者模式,我们可以定义设备的维护操作,并在不修改设备类的情况下添加新的维护行为。

案例场景

  • 设备元素:电脑(Computer)、手机(Phone)等设备。
  • 访问者:定义对设备执行维护操作的行为,如检查硬件(HardwareCheckVisitor)和更新软件(SoftwareUpdateVisitor)。
  • 对象结构:维护系统包含的所有设备,可以遍历设备并对它们执行维护操作。

代码实现

Step 1: 创建 Element 接口

// 定义元素接口
public interface Device {
    void accept(MaintenanceVisitor visitor);
}

Step 2: 创建具体元素类

// 具体元素:电脑类
public class Computer implements Device {
    @Override
    public void accept(MaintenanceVisitor visitor) {
        visitor.visitComputer(this);  // 调用访问者的访问方法
    }

    public String getName() {
        return "Computer";
    }
}

// 具体元素:手机类
public class Phone implements Device {
    @Override
    public void accept(MaintenanceVisitor visitor) {
        visitor.visitPhone(this);  // 调用访问者的访问方法
    }

    public String getName() {
        return "Phone";
    }
}

Step 3: 创建 Visitor 接口

// 访问者接口,定义对不同设备的访问方法
public interface MaintenanceVisitor {
    void visitComputer(Computer computer);
    void visitPhone(Phone phone);
}

Step 4: 创建具体的访问者

// 具体访问者:检查硬件
public class HardwareCheckVisitor implements MaintenanceVisitor {
    @Override
    public void visitComputer(Computer computer) {
        System.out.println("Checking hardware for " + computer.getName());
    }

    @Override
    public void visitPhone(Phone phone) {
        System.out.println("Checking hardware for " + phone.getName());
    }
}

// 具体访问者:更新软件
public class SoftwareUpdateVisitor implements MaintenanceVisitor {
    @Override
    public void visitComputer(Computer computer) {
        System.out.println("Updating software for " + computer.getName());
    }

    @Override
    public void visitPhone(Phone phone) {
        System.out.println("Updating software for " + phone.getName());
    }
}

Step 5: 创建对象结构

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

// 设备维护系统,包含一组设备
public class MaintenanceSystem {
    private List<Device> devices = new ArrayList<>();

    public void addDevice(Device device) {
        devices.add(device);
    }

    public void performMaintenance(MaintenanceVisitor visitor) {
        for (Device device : devices) {
            device.accept(visitor);  // 调用设备的 accept 方法
        }
    }
}

Step 6: 测试访问者模式

public class VisitorPatternDemo {
    public static void main(String[] args) {
        MaintenanceSystem system = new MaintenanceSystem();
        
        // 添加设备
        system.addDevice(new Computer());
        system.addDevice(new Phone());

        // 执行硬件检查
        MaintenanceVisitor hardwareCheck = new HardwareCheckVisitor();
        System.out.println("Performing hardware check:");
        system.performMaintenance(hardwareCheck);

        // 执行软件更新
        MaintenanceVisitor softwareUpdate = new SoftwareUpdateVisitor();
        System.out.println("\nPerforming software update:");
        system.performMaintenance(softwareUpdate);
    }
}

输出结果

Performing hardware check:
Checking hardware for Computer
Checking hardware for Phone

Performing software update:
Updating software for Computer
Updating software for Phone

总结

优点

  • 增加操作的灵活性:访问者模式允许你在不修改元素类的前提下增加新的操作。这使得添加新功能更加方便,尤其是在对象结构比较复杂的情况下。
  • 解耦操作和数据结构:访问者模式将操作行为与数据结构分离,避免了因为添加新操作而频繁修改数据结构的情况。
  • 集中管理操作:通过访问者模式,所有与特定类型对象相关的操作都可以集中在访问者中,便于代码的组织和管理。

缺点

  • **违背了迪米特法则:**具体元素对访问者公布细节,也就是说访问者关注了其他类的内部细节,这是迪米特法则所不建议的, 这样造成了具体元素变更比较困难
  • **违背了依赖倒转原则:**访问者依赖的是具体元素,而不是抽象元素

注意事项

  • 访问者模式适合对象结构稳定、但操作多变的场景。如果对象结构频繁变化,访问者模式的优势将大大降低,反而增加了维护成本
  • 元素类需要与访问者紧密配合,元素类必须提供接受访问者的方法。需要注意的是,如果访问者需要访问元素的私有数据,可能会破坏封装性,降低代码的可维护性

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

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

相关文章

在网络环境中怎么保护个人信息安全?

在网络环境中保护个人信息安全非常重要&#xff0c;以下是一些基本的建议来帮助您保护自己的个人信息&#xff1a; 使用强密码&#xff1a;确保您的所有在线账户都使用强密码。强密码通常包含大写字母、小写字母、数字以及特殊字符&#xff0c;并且长度至少为12位以上。 启用双…

【Node.js】初识微服务

概述 Node.js 的微服务架构是一种通过将应用程序分解为独立的、松耦合的小服务的方式进行系统设计。 每个微服务负责处理一个特定的业务功能&#xff0c;并且这些服务可以独立开发、部署、扩展和管理&#xff0c;并且可以通讯。 它的核心思想就是解耦。 微服务和微前端是类…

《中国数据库前世今生》观后感:数据库与中国IT的崛起

文章目录 1. 数据库技术的演进与挑战2. 开发者眼中的数据库3. 数据库未来展望4. 结语 作为一名程序员&#xff0c;观看了《中国数据库前世今生》纪录片后&#xff0c;我感受到了数据库技术在中国发展的巨大变化。中国IT行业的快速崛起&#xff0c;数据库技术无疑扮演了重要角色…

2.C++中程序的语法基础--关键字与分隔符

现在回过头来看上一篇中所写的程序&#xff1a; #include <bits/stdc.h> using namespace std; int main() {// 程序主体cout << "HelloWorld" << endl; return 0; } 我们会看到许多英文单词&#xff0c;像"include"、“using”&…

智能车镜头组入门(四)元素识别

元素识别是摄像头部分中难度最大的一部分&#xff0c;也是我花时间最长的一部分&#xff0c;前前后后画了很长时间&#xff0c;最后还是勉勉强强完成了。 基础的元素识别主要有两个&#xff1a;十字&#xff0c;圆环&#xff0c;和斑马线。十字要求直行&#xff0c;圆环需要进…

科技修复记忆:轻松几步,旧照变清晰

在时间的长河中&#xff0c;旧照片承载着无数珍贵的记忆与故事。然而&#xff0c;随着岁月的流逝&#xff0c;这些照片往往变得模糊不清&#xff0c;色彩黯淡&#xff0c;令人惋惜。 幸运的是&#xff0c;随着科技的发展&#xff0c;我们有了多种方法来修复这些旧照片的画质&a…

【Python基础】Python模块(提高代码可维护性与重用性的关键)

本文收录于 《Python编程入门》专栏&#xff0c;从零基础开始&#xff0c;分享一些Python编程基础知识&#xff0c;欢迎关注&#xff0c;谢谢&#xff01; 文章目录 一、前言二、什么是Python模块&#xff1f;三、创建模块四、导入模块五、使用if __name__ "__main__&quo…

(黑马点评) 五、探店达人系列功能实现

5.1 发布和查看探店笔记 5.1.1 发布探店笔记 这块代码黑马已经完成了&#xff0c;在发布探店笔记界面&#xff0c;有两块内容是需要上传的。一是笔记内容&#xff0c;二是笔记配图。其中笔记配图部分黑马使用的是上传到本地前端服务器上面的。我我觉得可以将图片文件发布在阿里…

开始你的博客之旅:从零到一的详细指南

创建博客不仅是表达自我的方式&#xff0c;更是与世界分享知识、塑造个人品牌、甚至实现商业变现的强大工具。本文将详细介绍从确定主题到实际运营的每个步骤&#xff0c;帮助你顺利开启个人博客的旅程。 确定博客的主题和目标 在开始博客之前&#xff0c;首先要明确博客的主…

windows环境下安装python第三方包

python环境下&#xff0c;通常通过Anaconda来管理多个python环境&#xff1b; 即通过Anaconda创建python不用的虚拟环境&#xff1b; 1. 安装更新python第三方包&#xff0c;打开Anaconda&#xff0c;在右侧的搜索需要的python包并进行安装&#xff1b; 2.如果没有搜索到&…

【线性规划求解系列】MATLAB中使用linprog解决线性规划问题

linprog - 求解线性规划问题 - MATLAB - MathWorks 中国https://ww2.mathworks.cn/help/optim/ug/linprog_zh_CN.html 本文详细介绍了如何在MATLAB中使用linprog函数来解决各种类型的线性规划问题。首先概述了linprog的基本语法&#xff0c;随后通过五个具体实例演示了如何处理…

《中国数据库前世今生》纪录片观感:从古至今数据库的演变与未来

我的数据库之路&#xff1a;从新手到稳步前行 三年数据库开发的经历&#xff0c;让我从一名菜鸟程序员逐步成长为能够独立解决问题的开发者。这段时间里&#xff0c;我经历过迷茫、困惑&#xff0c;也感受过技术攻关后的成就感。最近看了腾讯云推出的《中国数据库前世今生》纪…

基于机器学习的注意力缺陷/多动障碍 (ADHD)(python论文+代码)HYPERAKTIV

简述 医疗保健领域的机器学习研究往往缺乏完全可重复性和可比性所需的公共数据。由于患者相关数据附带的隐私问题和法律要求&#xff0c;数据集往往受到限制。因此&#xff0c;许多算法和模型发表在同一主题上&#xff0c;没有一个标准的基准。因此&#xff0c;本文提出了一个公…

盘点BDC/ZCU方案常用的芯片

文章目录 1.前言2.方案概述3.主控芯片3.1 RH850/U2A3.2 TC39x3.3 E34303.4 CCFC3007、CCFC3012 4.电源芯片4.1 混合方案4.2 分立方案 5.电机驱动芯片5.1 多路半桥驱动5.2 多路预驱5.3 步进电机驱动5.4 H桥驱动5.4.1 TI的H桥驱动5.4.2 ST的H桥驱动 6.高边驱动芯片/低边驱动芯片6…

自定义项目授权文件生成与认证

基于 TrueLicense 生成的授权文件证书存在很多局限性。所用这里通过自定义的方式来实现一个License授权文件的生成&#xff01; 这里通过非对称加密RSA 的方式来创建 项目授权文件内容&#xff01; 需要注意项目打包后最好将class文件进行防反编译的操作&#xff01; 否则通过暴…

LVGL 控件之滑动条(lv_slider)

目录 一、概述二、滑块1、设置滑块当前值和范围值2、设置滑块部件的模式3、禁用单击4、事件5、API 函数 一、概述 滑动条对象看起来像是在 进度条 增加了一个可以调节的旋钮&#xff0c;使用时可以通过拖动旋钮来设置一个值。 就像进度条&#xff08;bar&#xff09;一样&…

828华为云征文|采用华为云Flexus云服务器X实例部署MQTT服务器完成设备上云

文章目录 一、前言1.1 开发需求1.2 Flexus云服务器介绍1.3 EMQX服务器 二、服务器选购2.1 登录官网2.2 选购服务器2.3 选择服务器区域2.4 选择服务器规格2.5 选择系统镜像2.6 选择存储盘2.7 配置密码2.8 配置云备份2.9 确认配置2.10 立即购买2.10 后台控制台 三、服务器登录3.1…

最佳软件测试基础入门教程4静态测试

静态测试 对工作产品&#xff08;文档和代码&#xff09;进行静态测试和分析&#xff0c;对提高产品质量有很大的帮助。本章介绍了静态测试的一般情况&#xff0c;以及所涉及的具体过程&#xff0c;包括其活动和必须填补的角色。我们描述了四种经过验证的技术和它们的具体优势…

【HarmonyOS 】编译报错:Install Failed: error: failed to install bundle

此问题是由于支付宝sdk兼容性造成的&#xff0c;目前只能删除支付宝sdk依赖&#xff0c;如下图所示操作&#xff0c;删除后需要点右上角的 Sync Now&#xff0c;并等待 Sync 结束 删除后还需要点右上角的 Sync Now&#xff0c;并等待 Sync 结束 uniapp解决方案&#xff1a; htt…

50个必须知道的VS代码扩展

我们即将浏览50个必须知道的VS Code扩展&#xff0c;这些扩展将大幅提高您的生产力&#xff0c;并帮助您像专业人士一样编码&#xff01; 1. TabNine TabNine 是一个基于AI的自动完成工具&#xff0c;它可以根据您的代码上下文和模式建议完成&#xff0c;通过智能自动完成提高…