訪問者模式
一、訪問者模式的概念
訪問者模式屬於行爲模式,它分離對象的數據和行爲,使用訪問者模式,可以在不修改已有類的情況下,增加新的操作角色和職責。
二、訪問者模式使用場景
1、當對象結構中的對象對應的類很少改變,但經常需要在此對象結構上定義新的行爲和操作方法。
2、當需要對對象結構新增加的行爲和操作,避免新的操作和行爲改變原來的對象類,可以使用該模式實現解耦合。
三、訪問者模式構建方法
1、抽象訪問者類(Visitor)
訪問者的對象抽象類,定義具體訪問者的共同接口和方法。
2、具體訪問者類(ConcreteVisitor)
具體訪問者類實現抽象訪問者類所聲明的接口和方法。
3、抽象節點類(Element)
抽象節點類聲明一個接受接口和方法,接受一個訪問者對象作爲一個參量。
4、具體節點類(ConcreteElement)
具體節點類實現了抽象節點類所定義的的接受接口和方法。
5、結構對象類(ObiectStructure)
結構對象類可以遍歷結構中的所有元素,可以提供一個高層次的接口,讓訪問者對象可以訪問每一個元素。
四、訪問者模式的示例
// VisitorPattern.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//
#include <iostream>
#include <string>
#include <list>
#define DELETE_PTR(p) {if(p!=nullptr){delete (p); (p)=nullptr;}}
using namespace std;
// 前置聲明
class StaffElement;
// 訪問者抽象類-客戶
class CustomerVisit
{
public:
virtual void customVisit(StaffElement *pStaffElement) = 0;
};
// 抽象節點類-營業廳員工
class StaffElement
{
public:
virtual void accepCustomer(CustomerVisit *CustomerVisit) = 0;
virtual string getName() = 0;
};
// 具體節點類-營業廳員工A
class StaffAElem : public StaffElement
{
public:
StaffAElem(string nameStr)
{
m_nameStr = nameStr;
}
virtual void accepCustomer(CustomerVisit *pCustomerVisit)
{
pCustomerVisit->customVisit(this);
}
virtual string getName()
{
return m_nameStr;
}
private:
string m_nameStr;
};
// 具體節點類-營業廳員工B
class StaffBElem : public StaffElement
{
public:
StaffBElem(string nameStr)
{
m_nameStr = nameStr;
}
virtual void accepCustomer(CustomerVisit *pCustomerVisit)
{
pCustomerVisit->customVisit(this);
}
virtual string getName()
{
return m_nameStr;
}
private:
string m_nameStr;
};
// 具體訪問者類-客戶A
class CustomerAVisit : public CustomerVisit
{
public:
virtual void customVisit(StaffElement *pStaffElement)
{
cout << "客戶A在營業廳裏通過->" << pStaffElement->getName() << "辦理業務" << endl;
}
};
// 具體訪問者類-客戶B
class CustomerBVisit : public CustomerVisit
{
public:
virtual void customVisit(StaffElement *pStaffElement)
{
cout << "客戶B在營業廳裏通過->" << pStaffElement->getName() << "辦理業務" << endl;
}
};
// 結構對象類-員工管理類
class StaffStructure : public StaffElement
{
public:
StaffStructure()
{
m_staffElemList.clear();
}
~StaffStructure()
{
for (auto iter : m_staffElemList)
{
DELETE_PTR(iter);
}
m_staffElemList.clear();
}
virtual void accepCustomer(CustomerVisit *pCustomerVisit)
{
for (auto iter : m_staffElemList)
{
iter->accepCustomer(pCustomerVisit);
}
}
string getName()
{
return m_nameStr;
}
void addStaffElem(StaffElement *pStaffElement)
{
m_staffElemList.push_back(pStaffElement);
}
void removeStaffElem(StaffElement *pStaffElement)
{
m_staffElemList.remove(pStaffElement);
}
private:
list<StaffElement*> m_staffElemList;
string m_nameStr;
};
int main()
{
cout << "----------------------訪問者模式-------------------------" << endl;
StaffAElem *pStaffAElem = new StaffAElem("營業廳員工A");
StaffBElem *pStaffBElem = new StaffBElem("營業廳員工B");
StaffStructure *pStaffStructure = new StaffStructure;
pStaffStructure->addStaffElem(pStaffAElem);
pStaffStructure->addStaffElem(pStaffBElem);
CustomerAVisit *pCustomerAVisit = new CustomerAVisit;
CustomerBVisit *pCustomerBVisit = new CustomerBVisit;
cout << "------------客戶A辦理業務--------------" << endl;
pStaffStructure->accepCustomer(pCustomerAVisit);
cout << "------------客戶B辦理業務--------------" << endl;
pStaffStructure->accepCustomer(pCustomerBVisit);
//DELETE_PTR(pStaffAElem); //已經在StaffStructure析構函數析構
//DELETE_PTR(pStaffBElem);
DELETE_PTR(pCustomerAVisit);
DELETE_PTR(pCustomerBVisit);
DELETE_PTR(pStaffStructure);
std::cout << "Hello World!\n";
getchar();
}
運行結果:
五、訪問者模式的優缺點
優點:
1、每一個類都有自己的明確職責,符合單一職責原則。
2、訪問者模式增加新的操作很容易,擴展性和靈活性好。
缺點:
1、增加新的節點類比較困難,每增加一個新的節點都要在抽象訪問類中增加
一個新的抽象接口和方法,並在每一個具體訪問者類中增加相應的具體接口和方法。
2、破壞封裝,具體節點類必須對外暴露自己的內部狀態和操作方法。
愛人生,愛微笑,一個愛分享的程序員。
能力有限,如有錯誤,多多指教。。。