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

devtools/2024/9/24 7:24:34/

一、访问者模介绍

访问者模式(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.ppmy.cn/devtools/104292.html

相关文章

​T​P​一​面​

male 20min 1. 请尽可能详细地说明&#xff0c;浏览器盒模型是什么&#xff1f;有哪几种&#xff0c;区别是什么&#xff1f;IE浏览器和现代浏览器默认的盒模型是哪种&#xff1f;你的回答中不要写出示例代码。 盒模型是CSS中一个非常重要的概念&#xff0c;它定义了元素在网…

Unity中保存数据的方法

一、概述 Unity中可用于持久化的方式有&#xff1a; 1&#xff09;通过ScriptableObject在可编辑模式下保存数据 2&#xff09;通过excel、json等文件实现数据的可持久化 二、ScriptableObject的使用 1、使用背景 假如需要制作子弹预设体&#xff0c;每个子弹上有speed速…

《PCI Express体系结构导读》随记 —— 第II篇 第7章 PCIe总线的数据链路层与物理层(2)

接前一篇文章&#xff1a;《PCI Express体系结构导读》随记 —— 第II篇 第7章 PCIe总线的数据链路层与物理层&#xff08;1&#xff09; 7.1 数据链路层的组成结构 数据链路层使用ACK/NAK协议发送和接收TLP&#xff0c;由发送部件和接收部件组成。其中&#xff0c;发送部件由…

C语言补习课

来源&#xff1a;黑马程序员 C语言常用占位符 1.%d 或 %i&#xff1a;用于输出有符号整数&#xff08;int&#xff09;。 2.%u&#xff1a;用于输出无符号整数&#xff08;unsigned int&#xff09;。 3.%f&#xff1a;用于输出浮点数&#xff08;float或double&#xff09…

【ubuntu使用笔记】Ubuntu Desktop 访问SMB共享文件夹

Ubuntu Desktop 访问SMB共享文件夹 Ubuntu Desktop 访问SMB共享文件夹文件夹打开 file managerother location输入 IP地址&#xff0c;smb://IP点击connect按钮正常进入 命令行安装客户端连接 Ubuntu Desktop 访问SMB共享文件夹 文件夹 打开 file manager other location 输入…

Spring Boot如何解决跨域问题?

1.什么是跨域&#xff1f; 跨域请求&#xff0c;就是说浏览器在执行脚本文件的ajax请求时&#xff0c;脚本文件所在的服务地址和请求的服务地址不一样。说白了就是ip、网络协议、端口都一样的时候&#xff0c;就是同一个域&#xff0c;否则就是跨域。这是由于Netscape提出一个…

【用Java学习数据结构系列】震惊,二叉树原来是要这么学习的(二)

看到这句话的时候证明&#xff1a;此刻你我都在努力 加油陌生人 个人主页&#xff1a;Gu Gu Study 专栏&#xff1a;用Java学习数据结构系列 喜欢的一句话&#xff1a; 常常会回顾努力的自己&#xff0c;所以要为自己的努力留下足迹 喜欢的话可以点个赞谢谢了。 作者&#xff…

LLaMA-Factory微调入门个人重制版

LLaMA-Factory微调入门个人重制版 说明&#xff1a; 首次发表日期&#xff1a;2024-08-30LLaMA-Factory 官方Github仓库&#xff1a; https://github.com/hiyouga/LLaMA-Factory 关于 本文是对LLaMA-Factory入门教程 https://zhuanlan.zhihu.com/p/695287607 的个人重制版&…