設計模式之訪問者模式-訪問一下唄!

一、訪問者模式的概念

訪問者模式屬於行爲模式,它分離對象的數據和行爲,使用訪問者模式,可以在不修改已有類的情況下,增加新的操作角色和職責。

二、訪問者模式使用場景

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、破壞封裝,具體節點類必須對外暴露自己的內部狀態和操作方法。


愛人生,愛微笑,一個愛分享的程序員。
能力有限,如有錯誤,多多指教。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章