访问者模式

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 =====>

 

posted @ 2022-04-03 23:16  f9q  阅读(93)  评论(0编辑  收藏  举报