一、访问者模式是什么?
访问者模式是一种行为型的软件设计模式,表示一个作用于某对象结构中的各元素的操作。使得在不改变各元素类的前提下,能定义作用于这些元素的操作。
该模式适合数据结构相对稳定且算法又易变化的系统。数据结构是被访问者,算法操作相当于访问者。
访问者模式的优点:
- 良好扩展性。扩展对元素的操作,只需要添加访问者。
- 满足单一职责原则。相关的操作封装为一个访问者,使得访问者职责单一。
- 解耦。数据结构自身和作用于它的操作解耦合。
访问者模式的缺点:
- 不易增加元素类。每增加一个元素类,访问者的接口和实现都要进行变化。
- 违背了依赖倒置原则。访问者依赖的是具体元素而不是抽象元素。
- 破坏封装。访问者可以获取被访问元素的细节。
二、访问者模式
2.1 结构图
客户端即Main主函数,对象结构中存放了被访问的元素集合以及遍历各个元素的方法,使得抽象访问者可以依次与具体元素对接,完成访问。
2.2 代码示例
场景描述:市长视察学校和企业。
//Visitor.h /****************************************************/ #pragma once #include <iostream> #include <vector> #include <string> #include <algorithm> using namespace std; class Visitor; // 抽象元素类-地点(被访问) class Place { public: // 构造函数 Place(string name) : m_name(name) {} // 接受访问 virtual void accept(Visitor* visitor) = 0; // 获取名字 string getName() { return m_name; } private: string m_name; }; // 具体元素类-学校 class School : public Place { public: // 构造函数 School(string name) : Place(name) {} // 接受访问 virtual void accept(Visitor* visitor); }; // 具体元素类-企业 class Enterprise : public Place { public: // 构造函数 Enterprise(string name) : Place(name) {} // 接受访问 virtual void accept(Visitor* visitor); }; // 抽象访问者 class Visitor { public: // 访问学校 virtual void visitSchool(School* school) = 0; // 访问企业 virtual void visitEnterprise(Enterprise* enterprise) = 0; }; // 具体访问者-市长 class Mayor : public Visitor { public: // 访问学校 virtual void visitSchool(School* school) { cout << "市长参观了:" << school->getName() << endl; cout << "对老师和学生表达了诚挚的慰问。" << endl; } // 访问企业 virtual void visitEnterprise(Enterprise* enterprise) { cout << "市长参观了:" << enterprise->getName() << endl; cout << "对企业的发展表示肯定。" << endl; } }; // 访问行为类 class Visiting { public: // 添加被访问地点 void add(Place* place) { places.push_back(place); } // 删除被访问地点 void remove(Place* place) { places.erase(std::remove(places.begin(), places.end(), place), places.end()); } // 进行访问 void accept(Visitor* visitor) { for (auto place : places) { place->accept(visitor); } } private: std::vector<Place*> places; };
//Visitor.cpp /****************************************************/ #include "Visitor.h" // 接受访问 void School::accept(Visitor* visitor) { visitor->visitSchool(this); } // 接受访问 void Enterprise::accept(Visitor* visitor) { visitor->visitEnterprise(this); }
//main.cpp /****************************************************/ #include <iostream> #include <string> #include "Visitor.h" using namespace std; int main() { Visiting *visiting = new Visiting(); Place *school = new School("东华大学"); Place *enterprise = new Enterprise("华为"); Visitor *mayor = new Mayor(); // 添加被访问对象 cout << "首日,"; visiting->add(school); visiting->add(enterprise); // 安排市长进行访问 visiting->accept(mayor); // 次日行程,删除某个被访问对象后再次访问 cout << "次日,"; visiting->remove(school); visiting->accept(mayor); // 删除 delete visiting; delete school; delete enterprise; delete mayor; visiting = nullptr; school = nullptr; enterprise = nullptr; mayor = nullptr; return 0; }
程序结果如下。
访问者模式使得访问操作与被访问元素解耦,同样是访问学校和企业,不同的访问者来干的事情和目的是不一样的,而这个不同的内容就可以在访问者类中实现。不过该模式不太适合增加新的元素,就像添加一个新的被访问对象-派出所,那每个访问者都要添加访问派出所的操作,违反了开闭原则。
三、总结
我尽可能用较通俗的话语和直观的代码例程,来表述我对访问者模式的理解,或许有考虑不周到的地方,如果你有不同看法欢迎评论区交流!希望我举的例子能帮助你更好地理解访问者模式。
如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!