将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。
简单的说,就是已经存在稳定的数据类。由于外部需求,需要访问特定的类成员。希望在不改变原数据类接口,仅通过增加外部模块实现需求。此模式,是行为模式中最复杂的一种模式。
此模式主要用于在存在多个同类型的数据类情况下,统一对这些数据类某个成员属性的访问方式。有助于将数据代码与业务代码解耦,可在不修改数据类的情况下自由增加访问方式业务。
上述分析了,此模式多用于存在多个同类型数据类,只访问这些类某个成员属性。例:电脑管家检测电脑,要一项一项检测,先功能检测、再驱动检测。其中功能检测,只检测各配件(GPU、声卡)的功能是否正常。驱动检测,只检测各配件驱动是否正常。(具体如何检测的,这里不做关注)
由上述电脑管家检测场景,可构建类图:
数据源类: GPU(CPartGpu)、声卡(CPartSoundCard),两者可抽象出基类电脑组件(CComputePartBase);
访问类: 功能访问(CVisitorFunction)、驱动访问(CVisitorDriver),两者可抽象访问基类(CVisitorBase);
管理类: 电脑管家(CSafeMgr)。
注: 在最初的访问者模式类图没有管理类的角色,这里为了方便客户端使用接口,才增加此类。实际场景中,只要运用到访问者模式思想即可,没有必要参照其实现方式生搬硬套。
编程环境
工程结构
Visitor/
├── compute_part_base.h
├── main.cc
├── Makefile
├── part_gpu.cc
├── part_gpu.h
├── part_sound_card.cc
├── part_sound_card.h
├── safe_manager.cc
├── safe_manager.h
├── visitor_base.h
├── visitor_driver.cc
├── visitor_driver.h
├── visitor_function.cc
└── visitor_function.h
源数据接口
其内部实现了Accept()接口,看下Accept()做了什么事情。
void CPartGpu::Accept(CVisitorBase *visitor)
{
if (NULL != visitor) {
visitor->VisitGpu(this);
} else {
GPU_LOGE("visitor is NULL!\n");
}
}
访问者接口
查看下VisitGpu()、VisitSoundCard()接口的实现:
int CVisitorDriver::VisitGpu(CPartGpu *gpu)
{
if (gpu->CheckDriver() <= 0) {
DRV_LOG("%s of Gpu Failed!\n", this->GetName().c_str());
} else {
DRV_LOG("%s of Gpu Success!\n", this->GetName().c_str());
}
return 0;
}
int CVisitorDriver::VisitSoundCard(CPartSoundCard *soundCard)
{
if (NULL == soundCard) {
DRV_LOGE("soundCard is NULL!\n");
}
if (soundCard->CheckDriver() <= 0) {
DRV_LOG("%s of SoundCard Failed!\n", this->GetName().c_str());
} else {
DRV_LOG("%s of SoundCard Success!\n", this->GetName().c_str());
}
return 0;
}
管理类
typedef enum
{
ITEM_DRIVER = 0,
ITEM_FUNCTION,
ITEM_ALL,
}ECheckItem;
class CSafeMgr
{
public:
CSafeMgr();
~CSafeMgr();
void AddPartArray(CComputePartBase *);
void Accept(CVisitorBase *visitor);
void CheckItem(ECheckItem item);
private:
CPartGpu *mpGpu;
CPartSoundCard *mpSoundCard;
CVisitorDriver theDriverCheck;
CVisitorFunction theFunctionCheck;
std::vector<CComputePartBase *> mPartArray;
};
电脑管家就是管理类的作用,主要用于整理所有源数据对象与访问者对象。实现各个场景接口,为客户端提供简单易用的接口。
具体实现:
void CSafeMgr::AddPartArray(CComputePartBase *pPart)
{
if (NULL == pPart) {
MGR_LOGE("pPart is NULL!\n");
return ;
}
mPartArray.push_back(pPart);
}
void CSafeMgr::Accept(CVisitorBase *visitor)
{
vector<CComputePartBase *>::iterator it;
for (it = mPartArray.begin(); it != mPartArray.end(); ++it) {
(*it)->Accept(visitor);
}
}
void CSafeMgr::CheckItem(ECheckItem item)
{
switch (item)
{
case ITEM_DRIVER:
Accept(&theDriverCheck);
break;
case ITEM_FUNCTION:
Accept(&theFunctionCheck);
break;
case ITEM_ALL:
Accept(&theDriverCheck);
Accept(&theFunctionCheck);
break;
default:
MGR_LOGW("No this item!\n");
break;
}
}
客户端代码
int main(int argc, char *argv[])
{
CSafeMgr theSafeMgr;
theSafeMgr.CheckItem(ITEM_ALL);
return 0;
}
因为设计了CSafeMgr接口,main代码就简单易懂,只是运用CSafeMgr检测指定项即可。其无需关注有多少配件和多少测试项,只需关注结果。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。