设计模式之访问者模式-访问一下呗!

一、访问者模式的概念

访问者模式属于行为模式,它分离对象的数据和行为,使用访问者模式,可以在不修改已有类的情况下,增加新的操作角色和职责。

二、访问者模式使用场景

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、破坏封装,具体节点类必须对外暴露自己的内部状态和操作方法。


爱人生,爱微笑,一个爱分享的程序员。
能力有限,如有错误,多多指教。。。

posted @ 2020-03-05 22:33  ISmileLi  阅读(6)  评论(0编辑  收藏  举报