访问者模式

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 @   f9q  阅读(96)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
历史上的今天:
2016-04-03 Android内存管理(12)*「实例」用Monitor 生成.hprof文件 并分析内存泄漏
点击右上角即可分享
微信分享提示