访问者模式
1.相关文档
https://refactoring.guru/design-patterns/visitor
https://www.tutorialspoint.com/design_pattern/visitor_pattern.htm
2. 为什么要用访问者模式,解决了什么问题
2.1 问题场景
有一个无向图,目前的需求是把它广度优先遍历,把取出的数据存生成一个xml文件,有一天,需求变了,要求导出一个pdf文件,有一天又变了需求导出一个doc文档,后来又要求同时支持上面几个文件格式了。这个展出无向图数据的类要如何实现?每次都修改顶点的导出函数?违反了开-闭原则,而且每次修改都可能引出新的bug.
2.2 解决方案
针对上面的问题,如果把导出成文件这个行为封装成接口Visitor,其中的方法形参为顶点数据,其实现类完成各自的导出功能,顶点不再依赖具体实现,就可以解决上面的问题。这时顶点被抽象为Acceptor,把自己传送给Visitor.
这就是访问者模式的设计思想。把对象、复杂数据和业务、行为分离。访问者遍历受访者的数据并由访问者完成业务功能。
3.要点
3.1 优点
- 在数据不变的情况下,扩展Visitor就可扩展功能而不修改原数据类。
- 与迭代器模式相比,支持业务行为并且可扩展。
3.2 缺点
- 每增加一个新的数据,都要改变访问者接口及它的实现类。
4.类图
5.示例
5.1 访问者接口visitor.h
#ifndef __VISITOR__H__
#define __VISITOR__H__
class A1;
class A2;
struct Visitor{
virtual void visit(const A1 *a1) const = 0;
virtual void visit(const A2 *a2) const = 0;
virtual ~Visitor() = default;
};
struct V1 : Visitor{
void visit(const A1 *a1) const override;
void visit(const A2 *a2) const override;
};
struct V2 : Visitor{
void visit(const A1 *a1) const override;
void visit(const A2 *a2) const override;
};
#endif //__VISITOR__H__
5.2 受访者接口acceptor.h
#ifndef __ACCEPTOR__H__
#define __ACCEPTOR__H__
struct Acceptor{
virtual void accept(const Visitor *v)const = 0;
virtual ~Acceptor() = default;
};
struct A1 : Acceptor{
void accept(const Visitor *vistor)const override;
~A1();
};
struct A2 : Acceptor{
void accept(const Visitor *vistor)const override;
~A2();
};
#endif //__ACCEPTOR__H__
5.3 复合数据类composite.h
#ifndef __COMPOSITE__H_
#define __COMPOSITE__H_
struct Composite{
vector<const Acceptor*> data;
Composite();
~Composite();
void accept(const Visitor *visitor);
void add(const A1 *a1);
void add(const A2 *a2);
};
#endif //__COMPOSITE__H_
5.4 各类的实现main.cpp
#include <iostream>
#include <vector>
using namespace std;
#include "visitor.h"
#include "acceptor.h"
#include "composite.h"
//-------visitor------=====--------=-=-=-=-==-=-------=====--------------------==----
void V1::visit(const A1 * a1) const {
cout << "V1 visit a1 ----->" << endl;
}
void V1::visit(const A2 * a2) const {
cout << "V1 visit a2 ----->" << endl;
}
void V2::visit(const A1 * a1) const {
cout << "V2 visit a1 =====>" << endl;
}
void V2::visit(const A2 * a2) const {
cout << "V2 visit a2 =====>" << endl;
}
//-------acceptor------=====--------=-=-=-=-==-=-------=====--------------------==----
void A1::accept(const Visitor *visitor)const {
visitor->visit(this);
}
A1::~A1(){
// cout << __func__ << endl;
}
void A2::accept(const Visitor *visitor)const {
visitor->visit(this);
}
A2::~A2(){
// cout << __func__ << endl;
}
//-------composite------=====--------=-=-=-=-==-=-------=====--------------------==----
Composite::Composite(){
A1 *a1 = new A1();
A2 *a2 = new A2();
data.push_back(a1);
data.push_back(a2);
}
Composite::~Composite(){
for (const Acceptor *acceptor : data){
delete acceptor;
}
data.clear();
}
void Composite::accept(const Visitor *visitor){
for (const Acceptor *acceptor : data){
acceptor->accept(visitor);
}
}
void Composite::add(const A1 * a1){
data.push_back(a1);
}
void Composite::add(const A2 * a2){
data.push_back(a2);
}
//main
int main(int argc, char const *argv[]){
Composite composite;
V1 vsitor1; //----->
V2 vsitor2; //=====>
composite.accept(&vsitor1);
composite.accept(&vsitor2);
return 0;
}
5.5 运行结果
两个访问者v1 和 v2 ,它们分别访问了composite对象,且产生了不同的结果。
V1 visit a1 ----->
V1 visit a2 ----->
V2 visit a1 =====>
V2 visit a2 =====>