访问者模式
在GOF的《设计模式:可复用面向对象软件的基础》一书中对访问者模式是这样说的:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。访问者模式把数据结构和作用于结构上的操作之间的耦合解脱开,使得操作集合可以相对自由地演化。该模式的目的是要把处理从数据结构分离出来。访问者模式让增加新的操作很容易,因为增加新的操作就意味着增加一个新的访问者。访问者模式将有关的行为集中到一个访问者对象中。现在再来说说我之前经历过的那个项目。
使用场合
1.一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作;
2.需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。Visitor使得你可以将相关的操作集中起来定义在一个类中;
3.当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作;
4.定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
代码实现
// VisitorMode.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <iostream>
#include <vector>
using namespace std;
/
/*
* 双分派技术:
* 函数调用哪一个有一下两点决定:1.消息接收者的类型 2.参数类型
* C++只支持单分派,这里做一下dynamic_cast动态转换,提前检测一下接收者的类型
*/
/
/
// 关键词:数据结构和数据操作分离;不同访问者产生不同结果; 行为模型;
//
// 场景:主要操作复杂元素对象。元素对象无须改变,元素的执行算法随着访问者改变而改变
//
// 案列说明:
// 公司有几本账,有大老板和二老板,两个人时长查阅账本,
// 大老板权限大,可以看所有账目
// 二老板权限小,只可以看部分账目
//
// 扩展实例1:大老板老婆,权限比大老板还要大,继承于大老板
//
///接口//
//接口特征:Visit和Accept接口,两个接口都有参数,都是对方类指针
// Visit接口有多个重载
class ZhengBen;
class zhichu_ZhengBen;
class shouru_ZhengBen;
class LingDao //访问者
{
public:
virtual void Visit(ZhengBen *pZhengBen) = 0;
virtual void Visit(zhichu_ZhengBen *pZhengBen) = 0;
virtual void Visit(shouru_ZhengBen *pZhengBen) = 0;
};
class ZhengBen //元素类
{
public:
virtual void Accept(LingDao *pLingDao) = 0;
};
//
class DaLaoBan;
class ErLaoBan;
class zhichu_ZhengBen : public ZhengBen
{
public:
virtual void Accept(LingDao *pLingDao)
{
pLingDao->Visit(this);
}
public:
void ShowAll()
{
printf("展示-支出-所有内容\n");
}
void ShowPart()
{
printf("展示-支出-部分内容\n");
}
};
class shouru_ZhengBen : public ZhengBen
{
public:
virtual void Accept(LingDao *pLingDao)
{
pLingDao->Visit(this);
}
public:
void ShowAll()
{
printf("展示-收入-所有内容\n");
}
void ShowPart()
{
printf("展示-收入-部分内容\n");
}
};
//大老板
class DaLaoBan : public LingDao
{
public:
virtual void Visit(ZhengBen *pZhengBen)
{
;
}
virtual void Visit(zhichu_ZhengBen *pZhengBen)
{
pZhengBen->ShowAll();
}
virtual void Visit(shouru_ZhengBen *pZhengBen)
{
pZhengBen->ShowAll();
}
};
//二老板
class ErLaoBan : public LingDao
{
public:
virtual void Visit(ZhengBen *pZhengBen)
{
;
}
virtual void Visit(zhichu_ZhengBen *pZhengBen)
{
pZhengBen->ShowPart();
}
virtual void Visit(shouru_ZhengBen *pZhengBen)
{
pZhengBen->ShowPart();
}
};
//扩展实例,大老板娘
class DaLaoBanNiang: public DaLaoBan
{
};
int _tmain(int argc, _TCHAR* argv[])
{
zhichu_ZhengBen *pzhichu_ZhengBen = new zhichu_ZhengBen;
//大老板看
pzhichu_ZhengBen->Accept(new DaLaoBan);
//二老板看
pzhichu_ZhengBen->Accept(new ErLaoBan);
//大老板娘看
pzhichu_ZhengBen->Accept(new DaLaoBanNiang);
return 0;
}
总结
设计模式中经常说的一句话是:发现变化并封装之。是否采用访问者模式,就要看“变化”是什么。访问者模式中,“变化”是具体访问者,其次是对象结构;但是,如果具体元素也会发生改变,就万万不能使用访问者模式,因为这样“牵一发而动全身”,后期的维护性就太差了。