访问者模式(Visitor)

news2025/1/14 18:11:48

参考:

模板方法设计模式 (refactoringguru.cn)

design-patterns-cpp/TemplateMethod.cpp at master · JakubVojvoda/design-patterns-cpp · GitHubhttps://github.com/JakubVojvoda/design-patterns-cpp/blob/master/state/State.cpp)

文章目录

    • 一、什么是访问者模式?
    • 二、实现
    • 三、优缺点
      • 优点
      • 缺点
    • 四、适用环境

一、什么是访问者模式?

在软件构建过程中,由于需求的改变,某些类层次结构中常常需要增加新的行为(方法),如果直接在基类中做这样的更改,将会给子类带来很繁重的变更负担,甚至破坏原有设计。

访问者模式定义:表示一个作用于某对象结构中的各元素的操作。使得可以在不改变(稳定)各元素的类的前提下定义(扩展)作用于这些元素的新操作(变化)。

假如你需要将数据对象存储到xml文件中,而这样的数据类型有很多种。你不可能为每个类添加一个存储为xml的方法,因为后续可能又需要将数据存储其它格式,比如json,csv等。而存储的实现,又需要访问所有数据类的具体成员,这个时候,访问者模式可以很好地解决这个问题。

在这里插入图片描述

二、实现

访问者(Visitor)模式主要包含以下角色:

1、访问者(Visitor):接口,声明了一系列以对象结构的具体元素为参数的访问者方法。如果编程语言支持重载,这些方法的名称可以是相同的,但是其参数一定是不同的。

2、具体访问者(Concrete­ Visitor):会为不同的具体元素类实现相同行为的几个不同版本。

3、元素(Element):接口,声明了一个方法来接收访问者。该方法必须有一个参数被声明为访问者接口类型。

4、具体元素(Concrete Element):必须实现接收方法。该方法的目的是根据当前元素类将其调用重定向到相应访问者的方法。请注意,即使元素基类实现了该方法,所有子类都必须对其进行重写并调用访问者对象中的合适方法。

在这里插入图片描述

/*
 * C++ Design Patterns: Visitor
 * Author: Jakub Vojvoda [github.com/JakubVojvoda]
 * 2016
 *
 * Source code is licensed under MIT License
 * (for more details see LICENSE)
 *
 */

#include <iostream>

class Element;
class ConcreteElementA;
class ConcreteElementB;

/*
 * Visitor
 * declares a Visit operation for each class of ConcreteElement
 * in the object structure
 */
class Visitor
{
public:
  virtual ~Visitor() {}
  
  virtual void visitElementA( ConcreteElementA* const element ) = 0;
  virtual void visitElementB( ConcreteElementB* const element ) = 0;
  // ...
};

/*
 * Concrete Visitors
 * implement each operation declared by Visitor, which implement
 * a fragment of the algorithm defined for the corresponding class
 * of object in the structure
 */
class ConcreteVisitor1 : public Visitor
{
public:
  ~ConcreteVisitor1() {}
  
  void visitElementA( ConcreteElementA* const )
  {
    std::cout << "Concrete Visitor 1: Element A visited." << std::endl;
  }
  
  void visitElementB( ConcreteElementB* const )
  {
    std::cout << "Concrete Visitor 1: Element B visited." << std::endl;
  }
  // ...
};

class ConcreteVisitor2 : public Visitor
{
public:
  ~ConcreteVisitor2() {}
  
  void visitElementA( ConcreteElementA* const )
  {
    std::cout << "Concrete Visitor 2: Element A visited." << std::endl;
  }
  
  void visitElementB( ConcreteElementB* const )
  {
    std::cout << "Concrete Visitor 2: Element B visited." << std::endl;
  }
  // ...
};

/*
 * Element
 * defines an accept operation that takes a visitor as an argument
 */
class Element
{
public:
  virtual ~Element() {}
  
  virtual void accept( Visitor &visitor ) = 0;
  // ...
};

/*
 * Concrete Elements
 * implement an accept operation that takes a visitor as an argument
 */
class ConcreteElementA : public Element
{
public:
  ~ConcreteElementA() {}
  
  void accept( Visitor &visitor )
  {
    visitor.visitElementA( this );
  }
  // ...
};

class ConcreteElementB : public Element
{
public:
  ~ConcreteElementB() {}
  
  void accept( Visitor &visitor )
  {
    visitor.visitElementB( this );
  }
  // ...
};


int main()
{
  ConcreteElementA elementA;
  ConcreteElementB elementB;
  
  ConcreteVisitor1 visitor1;
  ConcreteVisitor2 visitor2;
  
  elementA.accept(visitor1);
  elementA.accept(visitor2);
  
  elementB.accept(visitor1);
  elementB.accept(visitor2);
  
  return 0;
}

三、优缺点

优点

  • 开闭原则。你可以引入在不同类对象上执行的新行为,且无需对这些类做出修改。
  • 单一职责原则。可将同一行为的不同版本移到同一个类中。
  • 访问者对象可以在与各种对象交互时收集一些有用的信息。当你想要遍历一些复杂的对象结构(例如对象树),并在结构中的每个对象上应用访问者时,这些信息可能会有所帮助。

缺点

  • 部分客户端可能会受到算法框架的限制。
  • 通过子类抑制默认步骤实现可能会导致违反里氏替换原则。
  • 只要算法发生变化,你就可能需要修改所有的类。

四、适用环境

  • 如果你需要对一个复杂对象结构(例如对象树)中的所有元素执行某些操作,可使用访问者模式。
  • 当某个行为仅在类层次结构中的一些类中有意义,而在其他类中没有意义时,可使用该模式。

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

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

相关文章

【Python机器学习】Sklearn库中Kmeans类、超参数K值确定、特征归一化的讲解(图文解释)

一、局部最优解 采用随机产生初始簇中心 的方法&#xff0c;可能会出现运行 结果不一致的情况。这是 因为不同的初始簇中心使 得算法可能收敛到不同的 局部极小值。 不能收敛到全局最小值&#xff0c;是最优化计算中常常遇到的问题。有一类称为凸优化的优化计算&#xff0c;不…

数字货币市场风暴肆虐,币圈人应该把握哪些新的赛道机遇

11月11日&#xff08;周五&#xff09;美股盘前&#xff0c;曾经为全球第二大加密货币交易所FTX在推特发布了申请破产保护的声明&#xff0c;创始人SBF已经辞去CEO职务。据声明&#xff0c;FTX已经任命John J. Ray III 担任CEO&#xff0c;SBF还将协助相关破产事宜。据FTX在推特…

[附源码]Python计算机毕业设计Django面向高校活动聚App

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

记录--三分钟打造自己专属的uni-app工具箱

这里给大家分享我在网上总结出来的一些知识&#xff0c;希望对大家有所帮助 介绍 可曾想过我们每次创建新项目&#xff0c;或者换地方写程序&#xff0c;都要把之前写过的工具类找出来又要复制粘贴一遍有些麻烦&#xff0c;尤其是写uni-app自定义模板主要还是开发工具完成的。这…

反序列化漏洞之CVE-2016-7124

目录 魔术函数 发生条件 靶场练习 魔术函数 __constuct: 构建对象的时被调用 __destruct: 明确销毁对象或脚本结束时被调用 __invoke: 当以函数方式调用对象时被调用 __toString: 当一个类被转换成字符串时被调用 __wakeup: 当使用unserialize时被调用&#xff0c;可用于做些…

【python】pandas 之 DataFrame、Series使用详解

目录 一&#xff1a;Pandas简介 二&#xff1a;Pandas数据结构 三&#xff1a;Series 四&#xff1a;字典生成Series 五&#xff1a;标量值生成Series 六&#xff1a;Series类似多维数组 七&#xff1a;Series类似字典 八&#xff1a;矢量操作与对齐 Series 标签 九…

对话交通银行:中国金融业数据仓库有哪些重要趋势?

数字经济时代&#xff0c;什么才是金融机构的核心竞争力&#xff1f;笔者访谈了交通银行软件开发中心总经理刘雷。刘雷指出&#xff1a;“数据和数据能力是金融机构发展的核心竞争力”。 当下&#xff0c;金融机构的数字化转型正迈入纵深阶段&#xff0c;使得两大核心诉求更加…

SpringMVC学习:四、SpringMVC的高级开发(异常处理器、文件上传、 拦截器)

5. SpringMVC的高级开发 5.1 异常处理器 ​ springmvc在处理请求过程中出现异常信息交由异常处理器进行处理&#xff0c;自定义异常处理器可以实现一个系统的异常处理逻辑。 思路: ​ 系统中异常包括两类&#xff1a;预期异常和运行时异常RuntimeException&#xff0c;前者…

如何利用代理IP做SEO监控优化?

从事互联网营销相关的用户多多少少都会接触到SEO&#xff0c;一般来说企业为了实现传播效果&#xff0c;每天都需要大量重复地做各种渠道的投放&#xff0c;这是一项逐渐累积的长期性工作。而这其中关键的优化分析与监控&#xff0c;势必需要大量的数据支持。接下来就一起来了解…

Linux--seq命令

seq(sequeue)用于序列化输出一个数到另一个数之间的整数&#xff0c;输出连续的数字、 固件间隔的数字、指定格式的数字。 一、使用方法 seq [选项] 尾数seq [选项] 首数 尾数seq [选项] 首数 增量 尾数 [选项] -f, --formatFORMAT use printf style floating-point FO…

深度学习 Day22——利用LSTM实现火灾温度预测

深度学习 Day22——利用LSTM实现火灾温度预测 文章目录深度学习 Day22——利用LSTM实现火灾温度预测一、前言二、我的环境三、LSTM介绍1、长期依赖的问题2、LSTM3、LSTM结构四、前期工作1、设置GPU2、导入数据3、数据可视化五、构建数据集1、设置X、y2、设置归一化3、划分数据集…

[附源码]Nodejs计算机毕业设计基于的校园失物招领平台Express(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程。欢迎交流 项目运行 环境配置&#xff1a; Node.js Vscode Mysql5.7 HBuilderXNavicat11VueExpress。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分…

[附源码]Python计算机毕业设计高校学生综合素质测评系统Django(程序+LW)

该项目含有源码、文档、程序、数据库、配套开发软件、软件安装教程 项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等…

分析Linux 内核 SCSI IO 子系统

【推荐阅读】 浅析linux内核网络协议栈--linux bridge virtio-net 实现机制【一】&#xff08;图文并茂&#xff09; 怎么在Windows下使用Makefile文件 概述 LINUX 内核中 SCSI 子系统由 SCSI 上层&#xff0c;中间层和底层驱动模块 [1] 三部分组成&#xff0c;主要负责管…

PreSTU:一个专门为场景文本理解而设计的简单预训练模型

摘要&#xff1a;在视觉与语言&#xff08;V&L&#xff09;模型中&#xff0c;阅读和推理图像中的文本的能力往往是缺乏的。我们如何才能学习出强大的场景文本理解&#xff08;STU&#xff09;的V&L模型呢&#xff1f;本文分享自华为云社区《场景文本理解预训练PreSTU》…

C#编程基础(万字详解,这一篇就够了)

C#及其开发环境简介 C#概述 C#的编程功能 C#与.Net的关系 .Net C# C#的集成开发环境 Windows上编写C#程序 Linux/Mac OS上编写C#程序 运行第一个HelloWorld程序 C#基本语法 程序实例 C#基本语法 using关键字 class关键字 注释 成员变量 成员函数 实例化一个类…

【图像分割】粒子群优化指数熵图像分割【含Matlab源码 287期】

⛄一、图像分割简介 理论知识参考&#xff1a;【基础教程】基于matlab图像处理图像分割【含Matlab源码 191期】 ⛄二、部分源代码 %%无递推 clc; clear; Cimread(‘1.jpg’); Crgb2gray©; %Cimnoise(C,‘gaussian’,0,0.005); figure subplot(1,2,1) imshow© tic …

vue初级入门以及demo实现详解

vue的初级入门1&#xff0c;vue是什么2&#xff0c;vue的特点2.1&#xff0c;采用组件化模式2.2&#xff0c;声明式编码2.3&#xff0c;虚拟DOM Diff算法3&#xff0c;vue的环境的基本配置和使用3.1&#xff0c;在浏览器安装开发工具3.2&#xff0c;开发环境3.3&#xff0c;de…

C++--数据结构--图的相关概念及模拟实现--高阶0712

1. 图的基本概念 图&#xff08;G&#xff09;是由顶点&#xff08;V&#xff09;集合及顶点间的关系&#xff08;边 E&#xff09;组成的一种数据结构&#xff1b; 顶点&#xff1a;图中的结点&#xff0c;第i个顶点记作vi。 两个顶点vi和vj相关称作vi和vj之间有一条边。 …

04查找算法:顺序查找法、二分查找法

开始系统学习算法啦&#xff01;为后面力扣和蓝桥杯的刷题做准备&#xff01;这个专栏将记录自己学习算法是的笔记&#xff0c;包括概念&#xff0c;算法运行过程&#xff0c;以及代码实现&#xff0c;希望能给大家带来帮助&#xff0c;感兴趣的小伙伴欢迎评论区留言或者私信博…