当前位置: 首页 > news >正文

【设计模式-访问者模式】

定义

访问者模式(Visitor Pattern)是一种行为型设计模式,允许你在不修改已有类的情况下向这些类添加新的功能或行为。它通过将操作的执行逻辑从对象的类中分离出来,使得你可以在保持类的封闭性(符合开闭原则)的前提下为不同对象定义新的操作。

UML图

在这里插入图片描述

  • Visitor(访问者):定义了针对元素结构中每种类型元素的访问操作,通常通过重载 visit 方法实现。
  • Element(元素接口或抽象类):定义了一个 accept(Visitor visitor) 方法,允许访问者访问自己。
  • ConcreteElement(具体元素):实现了 Element 接口,并在 accept 方法中调用访问者的对应方法,如 visitor.visit(this)。
  • ConcreteVisitor(对象结构):可以是一个包含不同类型元素的集合,它负责遍历元素并对每个元素调用 accept 方法。

优点

  • 开闭原则:可以在不修改现有类的情况下添加新的操作。
  • 单一职责原则:通过将元素的操作行为封装到访问者中,元素类的职责得以简化。
  • 可扩展性强:可以为对象结构中的类定义新的操作,而不改变类的定义。

缺点

  • 破坏封装性:访问者需要了解元素的内部细节,这可能破坏类的封装性。
  • 难以维护:如果元素类频繁变更,则需要更新所有访问者,访问者模式的维护成本可能较高。
  • 双重分派问题:访问者模式的实现涉及双重分派,即通过 accept 方法调用访问者的 visit 方法,这使得结构变得复杂。

代码

// 定义访问者接口
interface Visitor {void visit(Book book);void visit(Fruit fruit);
}// 定义元素接口
interface ItemElement {void accept(Visitor visitor);
}// 具体元素类 Book
class Book implements ItemElement {private String title;private double price;public Book(String title, double price) {this.title = title;this.price = price;}public String getTitle() {return title;}public double getPrice() {return price;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}// 具体元素类 Fruit
class Fruit implements ItemElement {private String name;private double weight;private double pricePerKg;public Fruit(String name, double weight, double pricePerKg) {this.name = name;this.weight = weight;this.pricePerKg = pricePerKg;}public String getName() {return name;}public double getWeight() {return weight;}public double getPricePerKg() {return pricePerKg;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}// 实现具体的访问者
class ShoppingCartVisitor implements Visitor {@Overridepublic void visit(Book book) {System.out.println("Book: " + book.getTitle() + ", Price: " + book.getPrice());}@Overridepublic void visit(Fruit fruit) {double cost = fruit.getWeight() * fruit.getPricePerKg();System.out.println("Fruit: " + fruit.getName() + ", Cost: " + cost);}
}// 测试访问者模式
public class VisitorPatternDemo {public static void main(String[] args) {ItemElement[] items = new ItemElement[] {new Book("Design Patterns", 50),new Fruit("Apple", 2, 3)};Visitor visitor = new ShoppingCartVisitor();for (ItemElement item : items) {item.accept(visitor); // 访问每个元素}}
}

场景

  • 对象结构稳定:当你的对象结构(类)相对固定,但需要在这个结构上添加新的操作时,访问者模式非常合适。这样可以避免修改已有类的代码。
  • 需要对多个类执行相似的操作:当你需要对多个不同类型的元素执行类似的操作时,使用访问者模式可以集中管理这些操作。
  • 复杂的对象结构:在处理复杂的对象结构时(例如树形结构),访问者模式可以提供清晰的访问逻辑,避免在每个元素中实现相同的逻辑。
  • 数据结构和操作分离:当你希望将数据结构与操作分离,以便于未来扩展时,访问者模式是一个良好的选择。这样可以保持类的单一职责原则。
  • 频繁变化的操作:如果你的操作逻辑频繁变化,但元素结构相对稳定,使用访问者模式可以方便地添加新的操作而不影响已有的元素类。
  • 需要对元素进行类型判断:访问者模式允许在访问者中根据元素的具体类型执行不同的操作,便于类型判断和特定处理。

具体示例

  • 编译器:在编译器中,抽象语法树(AST)需要执行不同的操作(如语义分析、优化等),访问者模式可以有效地管理这些操作。
  • 图形绘制:在图形编辑软件中,图形元素(如线条、圆形、矩形等)可以通过访问者模式实现不同的绘制和变换操作。
  • 文件系统:在文件系统中,可以定义访问者来实现文件的不同处理(如压缩、加密等),而不需要修改文件类的实现。
  • 账单处理:在购物车或账单系统中,可以使用访问者模式来处理不同类型的商品(如书籍、食品等),并计算总价或应用折扣。

总结

访问者模式适合于需要在多个元素上执行不同操作,且希望保持代码清晰和可扩展的情况。

相关文章:

【设计模式-访问者模式】

定义 访问者模式(Visitor Pattern)是一种行为型设计模式,允许你在不修改已有类的情况下向这些类添加新的功能或行为。它通过将操作的执行逻辑从对象的类中分离出来,使得你可以在保持类的封闭性(符合开闭原则&#xff…...

一元运算符(自增自减)

一、一元运算符 一元运算符,只需要一个操作数 1. 正号 正号不会对数字产生任何影响 2.-负号 负号可以对数字进行负号的取反 对于非Number的值,会将先转换为Number,在进行运算: 可以对一个其他的数据类型使用,来将其转换为n…...

gitlab/极狐-离线包下载地址

如果想要使用Gitlab/极狐进行数据的恢复,只能使用相同版本或者相近版本的安装包,因此有时候需要到它的官网上下载对应版本的安装包,以下是我收集到的对应地址的下载路径: Gitlab Gitlab离线库, https://packages.gitl…...

C++——输入三个整数,按照由小到大的顺序输出。用指针方法处理。

没注释的源代码 #include <iostream> using namespace std; void swap(int *m,int *n); int main() { int a,b,c; int *p1,*p2,*p3; cout<<"请输入三个整数&#xff1a;"<<endl; cin>>a>>b>>c; p1&a;p2&b;p3&c;…...

【Java8 重要特性】Lambda 表达式

文章目录 Lambda函数式接口Lambda 规则规范简化过程改写 Arrays.setAll()改写 Arrays.sort() forEach循环 list 集合循环 list 集合并输出对象信息循环 Map 集合 方法引用和构造器引用方法引用构造器引用 Lambda Lambda是一个匿名函数&#xff0c;我们可以将Lambda表达式理解为…...

word2vec--CBOW与Skip-Gram 两种模型

Word2Vec 是一种流行的用于生成词嵌入&#xff08;Word Embeddings&#xff09;的无监督学习模型&#xff0c;它由 Google 的一个团队在 2013 年提出。它的主要目的是将单词映射到一个连续的向量空间&#xff0c;使得语义相似的单词在这个空间中靠得更近。 Word2Vec 有两种主要…...

iOS六大设计原则设计模式

六大设计原则&#xff1a; 一、单一职责原则 一个类或者模块只负责完成一个职责或者功能。 类似于&#xff1a;UIView 和 CALayer 二、开放封闭原则 对扩展开放&#xff0c;对修改封闭。 我们要尽量通过扩展软件实体来解决需求变化&#xff0c;而不是通过修改已有的代码来…...

nacos 集群搭建

主机准备 IProle192.168.142.155slave02192.168.142.156slave192.168.142.157master 三台主机上分别构建 mysql 镜像 FROM mysql:8.0.31 ADD https://raw.githubusercontent.com/alibaba/nacos/develop/distribution/conf/mysql-schema.sql /docker-entrypoint-initdb.d/nac…...

STM32快速复习(十二)FLASH闪存的读写

文章目录 一、FLASH是什么&#xff1f;FLASH的结构&#xff1f;二、使用步骤1.标准库函数2.示例函数 总结 一、FLASH是什么&#xff1f;FLASH的结构&#xff1f; 1、FLASH简介 &#xff08;1&#xff09;STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分&…...

漏洞扫描工具使用

首先把补丁的两个文件复制下来替换原文件 找到C:\ProgramData\Acunetix\shared\license然后替换 然后打开漏扫工具并刷新页面 然后添加要扫描的网站 等他扫描完成 扫描完成就可以生成报告了 一共五十多页的报告...

C++ | Leetcode C++题解之第424题替换后的最长重复字符

题目&#xff1a; 题解&#xff1a; class Solution { public:int characterReplacement(string s, int k) {vector<int> num(26);int n s.length();int maxn 0;int left 0, right 0;while (right < n) {num[s[right] - A];maxn max(maxn, num[s[right] - A]);i…...

利士策分享,动摇时刻的自我救赎

利士策分享&#xff0c;动摇时刻的自我救赎 在人生的长河中&#xff0c;我们每个人都会面临各种挑战与抉择&#xff0c; 那些让人心生动摇的瞬间&#xff0c;如同夜空中偶尔掠过的乌云&#xff0c;遮蔽了前行的星光。 但正是这些动摇&#xff0c;构成了我们成长的轨迹&#x…...

动手学深度学习(李沐)PyTorch 第 1 章 引言

在线电子书 深度学习介绍 安装 使用conda环境 conda create -n d2l-zh python3.8 pip安装需要的包 pip install jupyter d2l torch torchvision下载代码并执行 wget https://zh-v2.d2l.ai/d2l-zh.zip unzip d2l-zh.zip jupyter notebookpip install rise如果不想使用jupyt…...

二叉树(二)深度遍历和广度遍历

一、层序遍历 广度优先搜索&#xff1a;使用队列&#xff0c;先进先出 模板&#xff1a; 1、定义返回的result和用于辅助的队列 2、队列初始化&#xff1a; root非空时进队 3、遍历整个队列&#xff1a;大循环while(!que.empty()) 记录每层的size以及装每层结果的变量&a…...

【算法——双指针】

922. 按奇偶排序数组 II 算法讲解050【必备】双指针技巧与相关题目_哔哩哔哩_bilibili main:vector<int>nums { 3,1,2,4 };int i 0, j 1;int n nums.size() - 1;while (j < nums.size() && i < nums.size()) //如果奇偶任一方排好了&#xff0c;另…...

Rocky Linux 9 中添加或删除某个网卡的静态路由的方法

使用ip命令配置临时路由 添加静态路由 ip route add <目的网络> via <下一跳IP> dev <网卡接口名称>例: 给eth0网卡添加一个到达 192.168.2.0/24 网络&#xff0c;下一跳为 192.168.1.254 的路由 ip route add 192.168.2.0/24 via 192.168.1.254 dev eth0…...

网站建设中常见的网站后台开发语言有哪几种,各自优缺点都是什么?

市场上常见的网站后台开发语言有PHP、Python、JavaScript、Ruby、Java和.NET等。这些语言各有其独特的优缺点&#xff0c;适用于不同的开发场景和需求。以下是对这些语言的具体介绍&#xff1a; PHP 优点&#xff1a;PHP是一种广泛用于Web开发的动态脚本语言&#xff0c;特别适…...

【程序大侠传】应用内存缓步攀升,告警如影随形

前序 在武侠编码的江湖中&#xff0c;内存泄漏犹如隐秘杀手&#xff0c;潜伏于应用程序的各个角落&#xff0c;悄无声息地吞噬着系统资源。若不及时发现和解决&#xff0c;必将导致内存枯竭&#xff0c;应用崩溃。 背景&#xff1a;内存泄漏的由来 内存泄漏&#xff0c;乃程序…...

JavaWEB概述

JavaWEB概述 一、什么是JavaWEB 用Java技术解决web互联网领域的技术栈。要学习JavaWEB首先得知道什么是客户端和服务端 客户端&#xff1a;简而言之&#xff0c;这就是使用方&#xff0c;比如我们下载一个软件去使用&#xff0c;里面有很多我们可以使用的功能&#xff0c;那…...

半结构化知识抽取案例

半结构化知识抽取是指从半结构化数据源&#xff08;如HTML、XML、JSON等&#xff09;中提取有用的信息&#xff0c;并将其转换为更易于理解和使用的知识形式。半结构化数据通常包含一些结构化的标记或标签&#xff0c;但不像完全结构化的数据那样严格。 比如抽取如下网页到neo …...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

Python 包管理器 uv 介绍

Python 包管理器 uv 全面介绍 uv 是由 Astral&#xff08;热门工具 Ruff 的开发者&#xff09;推出的下一代高性能 Python 包管理器和构建工具&#xff0c;用 Rust 编写。它旨在解决传统工具&#xff08;如 pip、virtualenv、pip-tools&#xff09;的性能瓶颈&#xff0c;同时…...

在Ubuntu24上采用Wine打开SourceInsight

1. 安装wine sudo apt install wine 2. 安装32位库支持,SourceInsight是32位程序 sudo dpkg --add-architecture i386 sudo apt update sudo apt install wine32:i386 3. 验证安装 wine --version 4. 安装必要的字体和库(解决显示问题) sudo apt install fonts-wqy…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...

uniapp 字符包含的相关方法

在uniapp中&#xff0c;如果你想检查一个字符串是否包含另一个子字符串&#xff0c;你可以使用JavaScript中的includes()方法或者indexOf()方法。这两种方法都可以达到目的&#xff0c;但它们在处理方式和返回值上有所不同。 使用includes()方法 includes()方法用于判断一个字…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库&#xff08;uthash库&#xff09;提供对哈希表的操作&#xff0c;文章如下&#xff1a; C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...

字符串哈希+KMP

P10468 兔子与兔子 #include<bits/stdc.h> using namespace std; typedef unsigned long long ull; const int N 1000010; ull a[N], pw[N]; int n; ull gethash(int l, int r){return a[r] - a[l - 1] * pw[r - l 1]; } signed main(){ios::sync_with_stdio(false), …...

【Qt】控件 QWidget

控件 QWidget 一. 控件概述二. QWidget 的核心属性可用状态&#xff1a;enabled几何&#xff1a;geometrywindows frame 窗口框架的影响 窗口标题&#xff1a;windowTitle窗口图标&#xff1a;windowIconqrc 机制 窗口不透明度&#xff1a;windowOpacity光标&#xff1a;cursor…...

使用python进行图像处理—图像变换(6)

图像变换是指改变图像的几何形状或空间位置的操作。常见的几何变换包括平移、旋转、缩放、剪切&#xff08;shear&#xff09;以及更复杂的仿射变换和透视变换。这些变换在图像配准、图像校正、创建特效等场景中非常有用。 6.1仿射变换(Affine Transformation) 仿射变换是一种…...

SE(Secure Element)加密芯片与MCU协同工作的典型流程

以下是SE&#xff08;Secure Element&#xff09;加密芯片与MCU协同工作的典型流程&#xff0c;综合安全认证、数据保护及防篡改机制&#xff1a; 一、基础认证流程&#xff08;参数保护方案&#xff09; 密钥预置‌ SE芯片与MCU分别预置相同的3DES密钥&#xff08;Key1、Key2…...