20行为型设计模式——访问者模式

news2024/11/13 14:33:13

一、访问者模介绍

访问者模式(Visitor Pattern)是一种行为型设计模式,用于将操作封装在访问者对象中,以便在不改变被访问对象的类的前提下,定义新的操作。它允许你在不修改现有代码的情况下,向对象结构中添加新的操作。例如:类data具有加、减、乘、除四种行为,通过访问者模式,允许在不修改现有代码的情况下,添加新的行为:取余、取整,这两个行为在访问者中实现。

访问者模式结构图

  1. 抽象访问者(Visitor):定义一个访问方法,用于访问每种具体元素的对象。通常包含一个visit方法,用于访问不同的元素类型。
  2. 具体访问者(ConcreteVisitor):实现抽象访问者接口,提供具体的操作实现。
  3. 元素接口(Element):定义一个接受访问者的方法。这个方法通常叫做accept,它将访问者作为参数。
  4. 具体元素(ConcreteElement):实现元素接口,并定义具体的accept方法,以调用访问者的相应访问方法。
  5. 对象结构(Object Structure):持有一组元素,并可以遍历这些元素,以便访问者能访问它们。通常是一个集合类,比如列表或集合。

二、访问者模式的设计方法

有一个公园,分为A、B两个区,公园的属性不变,有小溪、稀有的树种,珍贵的鸟类。该公园存在多个访问者:清洁工A负责打扫公园的A区,清洁工B负责打扫公园的B区,公园的管理者负责检点各项事务是否完成,上级领导可以视察公园,老百姓可以在公园放松和锻炼身体。也就是说,对于同一个公园,不同的访问者有不同的行为操作,而且访问者的种类也可能需要根据时间的推移而变化(行为的扩展性)。

visitor.cpp

#include <iostream>
#include <vector>
#include <string>

class Visitor;

class ParkElement {
public:
	virtual void accept(Visitor& visitor) = 0;
	virtual ~ParkElement() = default;
};

class ASection : public ParkElement {
public:
	void accept(Visitor& visitor) override;
	void cleanA() const {
		std::cout << "我在打扫公园A区树叶 " << std::endl;
	}
};

class BSection : public ParkElement {
public:
	void accept(Visitor& visitor) override;
	void cleanB() const {
		std::cout << "我在打扫公园B区树叶 " << std::endl;
	}
};

class Visitor {
public:
	virtual void visitASection(ASection& A) = 0;
	virtual void visitBSection(BSection& B) = 0;
	virtual ~Visitor() = default;
};

void ASection::accept(Visitor& visitor) {
	visitor.visitASection(*this);
}

void BSection::accept(Visitor& visitor) {
	visitor.visitBSection(*this);
}

class CleanerA : public Visitor {
public:
	void visitASection(ASection& A) override {
		std::cout << "代号为A的清洁工正在打扫公园A区垃圾 " << std::endl;
		std::cout << "A区员工回应: ";
		A.cleanA();
	}
	
	void visitBSection(BSection& B) override {}
};

class CleanerB : public Visitor {
public:
	void visitASection(ASection& A) override {}
	
	void visitBSection(BSection& B) override {
		std::cout << "代号为B的清洁工正在打扫公园B区垃圾 " << std::endl;
		std::cout << "B区员工回应: ";
		B.cleanB();
	}
};

class ParkManager : public Visitor {
public:
	void visitASection(ASection& A) override {
		std::cout << "公园管理者正在检查公园A区卫生 " << std::endl;
	}
	
	void visitBSection(BSection& B) override {
		std::cout << "公园管理者正在检查公园B区卫生 " << std::endl;
	}
};

class Supervisor : public Visitor {
public:
	void visitASection(ASection& A) override {
		std::cout << "上级领导正在视察公园A区卫生情况 " << std::endl;
	}
	
	void visitBSection(BSection& B) override {
		std::cout << "上级领导正在视察公园B区卫生情况 " << std::endl;
	}
};

class Tourist : public Visitor {
public:
	void visitASection(ASection& A) override {
		std::cout << "啊,多么美丽的A区! " << std::endl;
	}
	
	void visitBSection(BSection& B) override {
		std::cout << "啊,多么美丽的B区! " << std::endl;
	}
};

class Park {
public:
	void addElement(ParkElement* element) {
		elements.push_back(element);
	}
	
	void accept(Visitor& visitor) {
		for (auto* element : elements) {
			element->accept(visitor);
		}
	}
	
	void simulateParkEnvironment() {
	    printf("嗨,我是这座美丽的公园,一个被绿意环绕,处处洋溢着生命力的地方。当我睁开我那翠绿的眼帘,清晨的光线轻柔地投射在我的脸颊,唤醒了我沉睡的灵魂。\n");
	    printf("我拥抱着蜿蜒的小径,它们如血管般在我的身体里延伸,引领着人们踏上通往宁静与和谐的旅程。我是树木的家园,高大的树干是我的骨骼,茂盛的枝叶是我在蓝天上的画布。在这里,鸟儿在我的枝头歌唱,它们是我最美的音符。\n");
	    printf("我的湖泊是一位深邃的诗人,它用清澈的眼眸凝视着蓝天白云,倒映出四季的更替。我是花朵的花园,每一朵花都在我的怀抱中绽放,散发着它们的芬芳,吸引着蜜蜂与蝴蝶在我的世界中翩翩起舞。\n");
	    printf("我是孩子们的游乐园,我是情侣们的约会地,我是家庭们的野餐场。我是自然的博物馆,也是文化的聚集所。这里,每个人都能找到属于自己的一片天地,无论是独处静思,还是与朋友共享美好时光。\n");
	    printf("在我温柔的怀抱中,时间似乎变得缓慢而宁静。每一次呼吸,都是对大自然馈赠的感谢。我邀请你,快来探访我,和我一起沉醉在美丽的自然与宁静的和谐之中。\n");
	}
	
private:
	std::vector<ParkElement*> elements;
};

void doWorking() {
	Park park;
	ASection A;
	BSection B;
	
	park.addElement(&A);
	park.addElement(&B);
	
	CleanerA cleanerA;
	CleanerB cleanerB;
	ParkManager manager;
	Supervisor supervisor;
	Tourist tourist;
	std::cout << "\n=== Park self-introduction ===" << std::endl;
	park.simulateParkEnvironment();
	std::cout << "\n=== Cleaning Phase ===" << std::endl;
	park.accept(cleanerA);
	park.accept(cleanerB);
	std::cout << "\n=== Inspection Phase ===" << std::endl;
	park.accept(manager);
	park.accept(supervisor);
	std::cout << "\n=== Travel Phase ===" << std::endl;
	park.accept(tourist);
	return;
}

int main() {
	
	doWorking();
	return 0;
}

运行效果

 

三、访问者模式应用场景

1. 对象结构稳定,但需要增加新操作

当你有一个相对稳定的对象结构(如复杂的对象组合或树形结构),但需要频繁添加新的操作时,访问者模式非常适用。通过引入访问者,可以轻松扩展操作而无需修改对象结构。

2. 需要对不同类型的对象执行相似操作

如果你需要对多个不同类型的对象执行相似的操作,但这些对象的具体类型各不相同,访问者模式可以将操作的实现集中在访问者类中。例如,在图形处理应用中,可以定义一个访问者对不同形状(如圆形、矩形、三角形)进行统一的处理。

3. 复杂的对象结构遍历

当需要对复杂对象结构进行遍历并对每个对象执行某些操作时,访问者模式提供了一种清晰的方式。访问者可以定义多个重载的访问方法,使得对不同类型的对象执行操作时更为直观。

4. 需要在不同操作间共享代码

访问者模式允许不同的操作通过同一个访问者类进行代码重用,从而避免在对象类中重复实现相同的操作逻辑。这在处理大量类时特别有用,有助于减少代码冗余。

5. 降低对象之间的耦合性

使用访问者模式,可以将操作的定义与对象的实现分开,降低了对象之间的耦合性。这使得对象可以更加独立,便于进行单元测试和维护。

四、总结

访问者模式在需要对对象结构进行多次扩展操作而不希望修改对象结构本身的场景下非常有效。通过引入访问者,可以方便地添加新操作。值得注意的是访问者模式可能会破坏类的封装性,因为访问者模式要求访问者对象能够访问并调用每一个元素对象的操作,这有时会导致元素对象必须暴露一些内部操作和状态。这种暴露可能会破坏对象的封装性,从而增加系统的复杂性和潜在的错误风险。

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

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

相关文章

类和对象以及内存管理

对象拷贝时的编译器优化 现代编译器会为了尽可能提高程序的效率&#xff0c;在不影响正确性的情况下会尽可能减少⼀些传参和传返回值的过程中可以省略的拷贝。如何优化C标准并没有严格规定&#xff0c;各个编译器会根据情况自行处理。当前主流的相对新⼀点的编译器对于连续⼀个…

电池信息 v5.29.11 高级版,智能优化充电,最多可延长50%电池寿命

Charging Master 是一款非常实用的安卓 APP&#xff0c;专注于为您的手机充电提供最佳体验。借助其智能优化功能&#xff0c;Charging Master 能够最大程度地延长电池寿命&#xff0c;最多可达 50% 的节省。此外&#xff0c;该应用还提供了一系列功能&#xff0c;助您更好地管理…

提升团队效率的9款免费办公工具评测

本文主要介绍了以下9款协同办公软件&#xff1a;1.Worktile&#xff1b;2.PingCode&#xff1b;3.石墨文档&#xff1b;4.Teambition&#xff1b;5.蓝湖&#xff1b;6.工作宝&#xff1b;7.飞书&#xff1b;8.Asana&#xff1b;9.ClickUp。 在现代职场中&#xff0c;团队协作已…

GD - GD32350R_EVAL - PWM实验和验证1

文章目录 GD - GD32350R_EVAL - PWM实验和验证1概述笔记实验设计实验环境GD32350R_EVAL 的硬件连接修改程序配置 - 只产生PWM波&#xff0c;不要CMP清除波形TIMER0时钟设置TIMER0的PWM设置参数设置main()中PWM波形的开启代码示波器测量结果如果要产生4KHZ的PWM需要设置怎样的参…

在centos系统中kill掉指定进程

如上图&#xff0c;我想kill掉 python3 func_tg_1_vps.py这个进程&#xff08;而不kill掉python3 func_tg_2_vps.py&#xff09;。 解决方法&#xff1a; 第一步&#xff1a;首先使用ps -ef | grep python3命令&#xff0c;查出所有包含python3的命令 拿其中一条讲解 root …

开放式耳机漏音有多大?开放式耳机是否值得购买?

开放式耳机确实存在漏音的问题&#xff0c;这是因为其设计原理决定的。开放式耳机不像封闭式耳机那样完全封闭耳道&#xff0c;因此声音会向外散播&#xff0c;导致漏音。不过&#xff0c;随着技术的发展&#xff0c;许多耳机制造商已经开始着手解决这个问题&#xff0c;通过改…

Git之2.0版本重要特性及用法实例(五十六)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者. 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列…

VScode 使用记录

插件 1、代码提示插件&#xff1a;Codeium 安装说明&#xff1a;Codeium&#xff1a;强大且免费的AI智能编程助手 - Su的技术博客 (verysu.com) 用google账号登陆&#xff0c;跳转按照官网给的三个步骤来 step1&#xff1a;复制token&#xff1b; step2&#xff1a;在文件页…

中秋佳节,南卡Runner Pro5骨传导耳机让团圆更圆满!

中秋节&#xff0c;这个承载着温馨与团圆的节日&#xff0c;是向亲朋好友表达深情厚意的绝佳时刻。在这样一个特别的日子里&#xff0c;挑选一份既实用又充满科技感的礼物&#xff0c;无疑能够给人们带来惊喜与感动。南卡Runner Pro5骨传导耳机&#xff0c;凭借其创新的设计和卓…

绿色消费新动力:‘众店‘模式引领数字经济下的零售创新

在数字浪潮的推动下&#xff0c;传统零售业正经历着前所未有的转型。绿色消费积分系统&#xff0c;在这一变革中崭露头角&#xff0c;成为新兴消费平台的佼佼者。 一、"众店"平台的快速崛起 仅用两年时间&#xff0c;"众店"平台就实现了巨大的飞跃&#x…

代码随想录算法训练营day58:图论08:拓扑排序精讲;dijkstra(朴素版)精讲

拓扑排序精讲 卡码网&#xff1a;117. 软件构建(opens new window) 题目描述&#xff1a; 某个大型软件项目的构建系统拥有 N 个文件&#xff0c;文件编号从 0 到 N - 1&#xff0c;在这些文件中&#xff0c;某些文件依赖于其他文件的内容&#xff0c;这意味着如果文件 A 依…

4_PMSM基于s函数的仿真建模_1

为了检验电机仿真模型的正确性&#xff0c;&#xff0c;以基于s函数方法搭建的数学模型为例&#xff0c;搭建如图的三相所示的简单三相PMSM矢量控制系统&#xff0c;此模型忽略了PWM逆变器的影响。另外&#xff0c;感兴趣的同志可以对基于Simulink方法搭建的仿真模型进行验证。…

二叉树详解(2)

文章目录 4. 二叉树链式结构的实现5. 二叉树基础oj练习 4. 二叉树链式结构的实现 首先&#xff0c;我们先要了解一下二叉树的遍历顺序有哪些&#xff1a; 通过了解二叉树的遍历顺序&#xff0c;我们不难看出要实现二叉树的遍历需要用到递归&#xff0c;而使用递归我们就要思…

基于STM32开发的智能电力监控与管理系统

目录 引言环境准备工作 硬件准备软件安装与配置系统设计 系统架构硬件连接代码实现 系统初始化电流电压数据采集与处理能耗计算与负载管理OLED显示与状态提示Wi-Fi通信与远程监控应用场景 工业设施的电力监控与优化智能家居中的电力管理与节能常见问题及解决方案 常见问题解决…

【C++ 面试 - STL】每日 3 题(二)

✍个人博客&#xff1a;Pandaconda-CSDN博客 &#x1f4e3;专栏地址&#xff1a;http://t.csdnimg.cn/fYaBd &#x1f4da;专栏简介&#xff1a;在这个专栏中&#xff0c;我将会分享 C 面试中常见的面试题给大家~ ❤️如果有收获的话&#xff0c;欢迎点赞&#x1f44d;收藏&…

Code Practice Journal | Day58_Graph08 Topological Sorting

1. 概念 在一个有向无环图(DAG)中&#xff0c;根据节点的依赖关系&#xff0c;对所有的节点进行线性排序的算法 拓扑排序的结果不一定是唯一的 2. 实现 2.1 BFS&#xff08;卡恩算法&#xff09; 1、步骤 2、代码实现 以KamaCoder 117.软体构建 题目&#xff1a;117. 软件…

Stable Diffusion绘画 | 插件-宽高比调整助手:让计算器毕业

在调整图片宽高时&#xff0c;如果每次都需要用计算器根据比例算好&#xff0c;再手工输入&#xff0c;非常影响效率。 推荐使用以下的插件&#xff0c;来实现高效准确地调整图片宽高比例。 Aspect Ratio Helper 安装地址&#xff1a;https://github.com/thomasasfk/sd-webui…

80、k8s概念及组件介绍

一、k8s kubernetes:k8s----希腊语&#xff0c;舵手&#xff0c;飞行员 1.1、k8s作用&#xff1a; ​ 用于自动部署&#xff0c;扩展&#xff0c;管理容器化部署的应用程序。开源&#xff08;半开源。&#xff09; ​ k8s的底层语言是由go语言。 ​ k8s理解成负责自动化运…

Jetson Orin Nano GPIO 舵机

jetson orin nano 40针引脚扩展接头&#xff1a; 图源 Jetson Orin Nano Developer Kit User Guide - | NVIDIA Developer 引脚配置 使用jetson-io tool配置引脚&#xff1a; sudo /opt/nvidia/jetson-io/jetson-io.py 选择“Configure Jetson 40pin Header”: "Confi…

啥是纳米微纤维?咋制作?有啥用?

大家好&#xff0c;今天我们来聊聊纳米/微纤维——《Tailoring micro/nano-fibers for biomedical applications》发表于《Bioactive Materials》。这些纤维近年来备受关注&#xff0c;因为它们具有独特的功能和性质&#xff0c;在生物医学等领域有广泛应用。它们可以通过多种技…