技术成神之路:设计模式(十三)访问者模式

news2024/11/24 17:10:04

介绍

访问者模式(Visitor Pattern)是一种行为型设计模式,它允许你在不改变对象结构的前提下,定义作用于这些对象的新操作。这种模式通过将操作逻辑从对象结构中抽离出来,使得新的操作可以无缝地添加到现有对象中。

1.定义


访问者模式定义了一个访问者接口,它包含了访问不同元素的操作方法。具体的元素类接受访问者并调用相应的访问方法。通过这种分离,新增的操作可以直接通过访问者来实现,而不需要修改元素类。

2. 主要作用


  • 允许在不修改元素类的情况下,定义新的操作。
  • 提高了系统的可扩展性。
  • 避免了对复杂对象结构的直接修改。

3. 解决的问题


访问者模式解决了如何在不修改对象结构的情况下,向对象添加新的操作的问题。尤其在系统需要频繁添加新操作时,显得尤为重要。

4. 模式原理


包含角色:

  1. Visitor:定义了对各类元素对象的操作接口。
  2. ConcreteVisitor:实现Visitor接口,具体实现访问操作。
  3. Element:定义接受访问者的方法accept(), 通常由具体元素实现。
  4. ConcreteElement:实现Element接口,实现accept()方法。
  5. ObjectStructure:维护Element对象的集合,并提供遍历功能。

看到这么多的角色,就知道访问者模式并不简单,毕竟它是 《设计模式》中较为复杂的一个。不用怕,先以了解为主,因为它在实际开发中毕竟不常用。

UML类图:
在这里插入图片描述

示例:
假设我们有一个表示不同形状(如圆形和矩形)的对象结构,我们希望对这些形状执行不同的操作(如计算面积和绘制形状)。

定义形状接口和具体形状类:

// Shape接口
interface Shape {
    void accept(Visitor visitor);
}

// 圆形类
class Circle implements Shape {
    double radius;

    Circle(double radius) {
        this.radius = radius;
    }

    public double getRadius() {
        return radius;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

// 矩形类
class Rectangle implements Shape {
    double width;
    double height;

    Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    public double getWidth() {
        return width;
    }

    public double getHeight() {
        return height;
    }

    @Override
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
}

定义访问者接口和具体访问者类:

// 访问者接口
interface Visitor {
    void visit(Circle circle);
    void visit(Rectangle rectangle);
}

// 具体访问者类 - 计算面积
class AreaVisitor implements Visitor {
    @Override
    public void visit(Circle circle) {
        double area = Math.PI * circle.getRadius() * circle.getRadius();
        System.out.println("Circle area: " + area);
    }

    @Override
    public void visit(Rectangle rectangle) {
        double area = rectangle.getWidth() * rectangle.getHeight();
        System.out.println("Rectangle area: " + area);
    }
}

// 具体访问者类 - 绘制形状
class DrawVisitor implements Visitor {
    @Override
    public void visit(Circle circle) {
        System.out.println("Drawing a Circle with radius " + circle.getRadius());
    }

    @Override
    public void visit(Rectangle rectangle) {
        System.out.println("Drawing a Rectangle with width " + rectangle.getWidth() + " and height " + rectangle.getHeight());
    }
}

使用访问者模式:

public class VisitorPatternDemo {
    public static void main(String[] args) {
        Shape circle = new Circle(5);
        Shape rectangle = new Rectangle(4, 6);

        Visitor areaVisitor = new AreaVisitor();
        Visitor drawVisitor = new DrawVisitor();

        System.out.println("Calculating areas:");
        circle.accept(areaVisitor);
        rectangle.accept(areaVisitor);

        System.out.println("\nDrawing shapes:");
        circle.accept(drawVisitor);
        rectangle.accept(drawVisitor);
    }
}

打印输出:

Calculating areas:
Circle area: 78.53981633974483
Rectangle area: 24.0

Drawing shapes:
Drawing a Circle with radius 5.0
Drawing a Rectangle with width 4.0 and height 6.0

说真的,写到这里我还是懵懵的,但隐约感觉这个设计不错,哈哈哈。

举个栗子,假如你是个想了解学生信息的老师(Visitor),你可以是班主任也可以是体育老师(ConcreteVisitor),因为他们的关注点不同(例如,班主任关注学生的学习成绩,体育老师关注学生的运动能力),学校里的不同类型的学生(Element),具体的学生(ConcreteElement)(例如文艺生A,运动生B)。

此时,假设我们有一个学校系统,其中有多种学生类型和评价标准。

  • 学生接口(Student):定义一个 accept(Visitor visitor) 方法。
  • 具体学生(SpecificStudent):实现 Student 接口,能够接受不同的访问者。
  • 访问者接口(Visitor):定义访问不同学生类型的方法,如 visit(ArtStudent artStudent)visit(SportsStudent sportsStudent)
  • 具体访问者(ConcreteVisitor):实现具体的访问逻辑,比如 AcademicEvaluator 关注学术成绩,PhysicalEducationEvaluator 关注体育表现。

回头再看一遍定义,访问者模式定义了一个访问者接口,它包含了访问不同元素的操作方法,此处的不同元素就是不同的学生,具体的元素类接受访问者并调用相应的访问方法,此处的相应的访问方法就是 学术成绩 和 体育表现,通过这种方式,可以在不改变学生对象结构的前提下,增加新的评价逻辑或操作,而不需要修改学生类本身。

到这里,是不是更进一步了解访问者模式了,不明白也不要紧,记住定义就行了。我突然想到我高中数学老师说的一句话:别管为啥这样写,你就记住,这样写就给分!哈哈。有时候不必太纠结,现在不明白 后面你也会明白的😉

5. 优缺点


优点:

  1. 扩展性强:新增功能时无需改动现有类。
  2. 操作集中:相关操作集中在访问者中,易于维护。

缺点:

  1. 增加复杂性:增加了类的数量,可能使系统变得复杂。
  2. 难以扩展元素:如果需要增加新的元素类,则需要修改访问者接口和所有具体访问者。

6. 应用场景


  • 当需要对一组对象进行不同的操作而又不希望修改这些对象时。
  • 需要对对象结构进行多种操作而操作逻辑复杂的情况下。
  • 系统中的对象结构比较复杂且稳定,而操作经常变化时。

7. 总结


访问者模式是一种强大的设计模式,可以方便地向对象结构中添加新的操作,而无需修改对象结构本身。然而,这种模式也有其局限性,主要在于它要求对象结构相对稳定,在对象结构频繁变化的系统中使用会增加维护成本。因此,在使用访问者模式时,需要根据具体情况权衡其优缺点,选择合适的应用场景。

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

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

相关文章

【漏洞复现】用友 NC pagesServlet Sql注入漏洞

免责声明: 本文内容旨在提供有关特定漏洞或安全漏洞的信息,以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步,并非出于任何恶意目的。阅读者应该明白,在利用本文提到的漏洞信息或进行相关测…

安装docker-compose最新版本

github下载地址 在github上下载最新版本,这里是centos7的环境直接下载这个就好了。 这里下载好传到服务器即可,这里查看没有权限 需要给文件增加x的执行权限。 ~]# ls -lh 总用量 61M -rw-------. 1 root root 1.7K 7月 29 2022 anaconda-ks.cfg -rw-r…

【最新综述】基于深度学习的超声自动无损检测(下)

4.Levels of automation 5.Basic axioms for DL-based ultrasonic NDE 在回顾了最新技术和每个自动化级别的贡献之后,我们不难发现,目前的数字语言方法论在不同论文之间存在着很大的差异。例如,有些作者提出了同时处理不同步骤的模型[121]&…

【佳学基因检测】在EXCEL中,如何获取A列的第9-29个字符,将其填入另一列中

【佳学基因检测】在EXCEL中,如何获取A列的第9-29个字符,将其填入另一列中 在 Excel 中,如果你需要从 A 列的单元格中提取第 9 到第 29 个字符,你可以使用 MID 函数来实现。这是一个非常实用的函数,用于从文本字符串中…

Java设计模式之责任链模式详细讲解和案例示范

在本文中,我们将详细讲解Java设计模式中的责任链模式,探讨其基本概念、使用场景、常见问题和解决方式。同时,我们还会介绍责任链模式与策略模式的区别,并结合电商交易系统的示例进行说明。此外,我们还会探讨责任链模式…

新手c语言讲解及题目分享(十九)--数据类型专项练习

本文主要讲解c语言的基础部分,常见的c语言基础数据类型,这个也非常重要。 参考书目和推荐学习书目:通过网盘分享的文件:C语言程序设计电子教材 (1).pdf 链接: https://pan.baidu.com/s/1JFqSaCKZ0A2Lr944e72NUA?pwdp648 提取码: …

Golang协程泄漏定位和排查

1 场景:无缓冲channel写阻塞 package mainimport ("log""net/http"_ "net/http/pprof""time""github.com/gin-gonic/gin" )func main() {go func() {log.Println(http.ListenAndServe("localhost:6060&quo…

uni-app实现web-view和App之间的相互通信

双向实时 如果app端部署成网站&#xff0c;则web-view就是iframe&#xff0c;使用也可以双向通讯 https://uniapp.dcloud.net.cn/component/web-view.html APP端代码 index.vue: <template><web-viewid"m-webview":fullscreen"true":src"…

数据结构-二叉树-基础知识

数据结构-二叉树-基础知识 1.树1.1什么是树1.2基本概念子节点、父节点叶节点节点的度树的高度/深度节点的子孙、祖先 1.3树与非树1.4如何实现1.5实例 2.二叉树2.1什么是二叉树2.2特殊的二叉树满二叉树完全二叉树 2.3性质层数度节点 2.4存储结构 1.树 1.1什么是树 树型结构是一…

C#笔记10 Thread类怎么终止(Abort)和阻止(Join)线程

Thread类 C#笔记8 线程是什么&#xff1f;多线程怎么实现和操作&#xff1f;-CSDN博客 C#笔记9 对线程Thread的万字解读 小小多线程直接拿下&#xff01;-CSDN博客 上次说过怎么简单的使用多线程&#xff0c;怎么创建多线程&#xff0c;但是没有具体分析它的终止和释放。 线…

【C++题解】1330. 求最大梯形的面积

欢迎关注本专栏《C从零基础到信奥赛入门级&#xff08;CSP-J&#xff09;》 问题&#xff1a;1330. 求最大梯形的面积 类型&#xff1a;二维数组 题目描述&#xff1a; 从键盘读入 n ( 3≤n≤100 )个梯形的上底、下底和高&#xff0c;请问这 n 个梯形中&#xff0c;最大面积…

3.ChatGPT在教育领域的应用:教学辅助与案例分享(3/10)

ChatGPT在教育领域的应用&#xff1a;教学辅助与案例分享 引言 在21世纪的教育领域&#xff0c;技术革新正以前所未有的速度改变着传统的教学和学习方式。随着人工智能&#xff08;AI&#xff09;的快速发展&#xff0c;教育技术&#xff08;EdTech&#xff09;领域迎来了新的…

“后期分块”:用长上下文嵌入模型拯救文本检索

论文&#xff1a;Late Chunking: Contextual Chunk Embeddings Using Long-Context Embedding Models地址&#xff1a;https://arxiv.org/abs/2409.04701 研究背景 研究问题&#xff1a;这篇文章要解决的问题是文本块嵌入在处理长文本时丢失上下文信息的问题。具体来说&#xf…

信刻光盘安全隔离与信息交换系统

随着各种数据传输、储存技术、信息技术的快速发展&#xff0c;保护信息安全是重中之重。军工、政府、部队及企事业单位等利用A网与B网开展相关工作已成为不可逆转的趋势。针对于业务需要与保密规范相关要求&#xff0c;涉及重要秘密信息&#xff0c;需做到安全的物理隔离&#…

队列的详细操作

1.循环队列--队列的顺序表示和实现 #include<stdio.h> #define MAXQSIZE 100 typedef struct {int* base;int front;int rear; }SqQueue;int InitQueue(SqQueue& Q) {Q.base new int[MAXQSIZE];//为队列分配一个最大容量为MAXSIZE的数组空间if (!Q.base)return -1;…

QXml 使用方法

VS2019 QT 编译工具链问题解决 使用winqtdeploy.exe 打包环境就可以正常运行&#xff0c;缺少某一个运行库引起的 简易使用python脚本编译运行 Python3 中的 slots 和 QT 中的 slots 宏定义重复, 放在不同的文件中进行调用可以避免 还是比较习惯从源码包引入&#xff08;方便定…

OpenAI新“草莓”模型即将发布,推理模式引发关注

OpenAI发布“草莓”模型的消息引发广泛关注。这个新模型将在未来两周内亮相&#xff0c;将为ChatGPT等产品带来全新的技术支持。草莓模型的推理模式具有独特性&#xff0c;能够仿效人类思维&#xff0c;在生成响应之前进行拟人化思考。其推理过程通常需要10到20秒&#xff0c;这…

2_foc闭环调试_ADC电流采样与滤波及pid数据结构

1、ADC电流采样 上次添加了编码器获取电角度的程序&#xff0c;将之前开环控制的角度进行了替换&#xff0c;这次再将电流采样添加进来&#xff0c;之后就可以利用这样一个有反馈的系统进行电流环PI控制器参数调试。 之前写过ADC&#xff0b;DMA电流采样的stm32库函数程序&…

《 C++ 修炼全景指南:八 》智能指针大揭秘:从 auto_ptr 到 unique_ptr shared_ptr 的进化之路

1、引言 在 C 编程中&#xff0c;内存管理历来是复杂且容易出错的部分。手动管理动态分配的内存不仅会导致内存泄漏&#xff0c;还会引发悬空指针和双重释放等问题。如何有效地管理动态内存&#xff0c;避免内存泄漏和未定义行为&#xff0c;往往是困扰初学者和资深开发者的难…

常见 HTTP 状态码详解与Nginx 文件上传大小限制

在我们日常使用 Nginx 搭建网站或应用服务时&#xff0c;可能会遇到很多与文件上传和请求响应相关的问题。今天我们就来聊聊 如何限制文件上传的大小&#xff0c;并介绍一些常见的 HTTP 状态码 及其在 Nginx 中的处理方式。 一、文件上传大小限制 有时&#xff0c;我们需要限…