Behavior.Visitor访问者模式:算法与数据结构的分离

访问者模式是一种设计模式,旨在不修改对象结构的情况下添加新操作。它通过定义Visitor接口,让ConcreteVisitor实现特定功能,Element接受访问并回调访问者的功能。这种模式在扩展对象功能时提供了一种灵活的方式,避免对原有代码的修改,通过预留通路和回调实现功能添加。
访问者模式(Visitor Pattern)的定义

(1)定义:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作

  ①模式是要解决当为对象添加新的操作和功能时候,如何尽可能不修改对象的类的一种方法。一般为对象添加功能,是需要向对象添加成员函数,但这里是通过添加一个访问者,由访问者去实现对象需要的新功能。

  ②该模式主要是针对为一系列对象添加不同功能的。当然如果是简化版的话,也可以为一个对象添加新功能。

(2)访问者模式的结构和说明

 

  ①Visitor:访问者接口,为所有的访问者对象声明一个visit方法,用来代表为对象结构添加的功能,理论上可以代表任意的功能。

  ②ConcreteVisitor:具体的访问者实现对象,实现要真正被添加到对象结构中的功能。(如为元素A添加A功能,元素B添加B功能)。

  ③Element:抽象的元素对象,对象结构的顶层接口,定义接受访问的操作

  ④ConcreteElement:具体元素对象,对象结构中的具体对象,也是被访问的对象,通常会回调访问者的真实功能,同时开放自身的数据供访问者使用

  ⑤ObjectStructure:对象集合或复合,通常包含多个被访问对象,它可以遍历多个被访问的对象,也可以让访问者访问它的元素。

(3)思考访问者模式:本质——预留通路,回调实现

  ①访问者模式能给一系列对象透明的添加新的功能,从而避免在维护期间对这一系列对象进行修改,而且还能变相实现复用访问者所具有的功能。

  ②访问者模式主要是通过预先定义好调用的通路,在被访问的对象上定义accept方法,在访问者对象上定义visit方法

  ③然后在调用真正发生的时候,通过两次分发技术,利用预先定义好的通路,回调到访问者具体的实现上。

【编程实验】扩展客户管理的功能


//行为型模式——访问者模式
//场景:扩展客户管理的功能
/*
说明:
1. 公司客户分为企业客户和个人客户
2. 目前的功能:客户提出服务申请
3. 需要扩展的功能:
  (1)客户对公司产品的偏好分析。针对企业和个人客户有不同的分析策略。主要是根据以往购买的历史、潜在购买意向等分析。对于企业客户还要分析其所在行
     业的发展趋势、客户的发展预期等
  (2)客户价值分析。针对企业和个人客户,有不同的分析策略。主要根据购买的金额大小、购买的产品和服务的多少、购买的频率进行分析的。
4. 潜在功能:不同客户的需求调查、满意度分析、客户消费预期分析等。
解决方案:
1. 对象结构就两种:企业客户和个人客户,如何在不想改变类,又要添加新的功能。
2. 定义一个接口代表要新加入的功能。
3. 在客户上添加一个通用的accept方法传入代表新加入的功能对象。
4. 实现新功能对象。
5. 循环访问整个对象结构的类,让这个类来提供符合客户端业务需求的方法。
*/
#include <iostream>
#include <string>
#include <list>

using namespace std;

class CEnterpriseCustomer; //前置声明
class CPersonalCustomer;   //前置声明

//*****************************访问者的接口(Visitor角色)**************************
class CVisitor{
public:
	//访问个人客户对象,相当于给个人客户添加访问者的功能
	virtual void VisitPersonalCustomer(CPersonalCustomer* person) = 0;
	//访问企业客户,相当于给企业客户添加访问者的功能
	virtual void VisitEnterpriseCustomer(CEnterpriseCustomer* enterprise) = 0;
};
//**********************************被访问对象(Elment角色))*********************
//被访问对象,客户接口
class CCustomer{
private:
	string strId;
	string strName;
public:
	string& GetId(){return strId;}
	string& GetName(){return strName;}
	virtual void Accept(CVisitor* visitor) = 0;
	virtual ~CCustomer(){}//让子类的析构函数也得以调用
};
//个人客户
class CPersonalCustomer : public CCustomer{
private:
	string strTel;
	int iAge;
public:
	string& GetTel(){return strTel;}
	int& GetAge(){return iAge;}
	//回调访问者对象的相应方法
	void Accept(CVisitor* visitor){visitor->VisitPersonalCustomer(this);}
};
//企业客户
class CEnterpriseCustomer : public CCustomer{
private:
	string strContact;//联系人
	string strRegistAddr;//注册地址
public:
	string& GetContact(){return strContact;}
	string& GetRegistAddr(){return strRegistAddr;}
	//回调访问者对象的相应方法
	void Accept(CVisitor* visitor){visitor->VisitEnterpriseCustomer(this);}
};

//************************具体的访问者实现*******************************
//实现客户提出服务请求的功能
class CSrvReqVisitor : public CVisitor{
public:
	//个人客户提出的具体服务请求
	void VisitPersonalCustomer(CPersonalCustomer* person)
	{
		cout << "客户" << person->GetName() << "提出服务请求" << endl;
	}
	//企业客户提出的具体服务请求
	void VisitEnterpriseCustomer(CEnterpriseCustomer* enterprise)
	{
		cout << enterprise->GetName() << "企业提出服务请求" << endl;
	}
};

//实现对客户偏好的分析
class CPredilectionAnalyzeVisitor : public CVisitor{
public:
	//针对个人客户的分析
	void VisitPersonalCustomer(CPersonalCustomer* person)
	{
		//根据以往购买历史、潜在购意向以及客户所在行业的发展趋势
        //客户的发展预期等分析
		cout << "现在对个人客户" << person->GetName() << "进行产品偏好分析" << endl;
	}
	//针对企业客户的分析
	void VisitEnterpriseCustomer(CEnterpriseCustomer* enterprise)
	{
		cout << "现在对企业客户" << enterprise->GetName() << "进行产品偏好分析" << endl;
	}
};

//*********************************ObjectStructure角色*************************

void Visitor()
{
	list<CCustomer*> lstCustomer;//客户集合
	//准备一些测试数据,创建客户对象,并加入到
	CCustomer* pCustomer = new CEnterpriseCustomer();
	pCustomer->GetName() = "ABC集团"; lstCustomer.push_back(pCustomer);

	pCustomer = new CEnterpriseCustomer();
	pCustomer->GetName() = "XYZ集团"; lstCustomer.push_back(pCustomer);

	pCustomer = new CPersonalCustomer();
	pCustomer->GetName() = "张三"; lstCustomer.push_back(pCustomer);

	//客户提出服务请求,传入服务请求的Visitor
	CSrvReqVisitor oSrvReqVisitor;
	for(list<CCustomer*>::iterator it = lstCustomer.begin(); it !=lstCustomer.end(); it++){
		//循环对象结构中的元素,接受访问
		pCustomer = (*it); pCustomer->Accept(&oSrvReqVisitor);
	}

	//对客户进行偏好分析,传入偏好分析的Visitor
	CPredilectionAnalyzeVisitor oPredilectionAnalyzeVisitor;
	for(list<CCustomer*>::iterator it = lstCustomer.begin(); it !=lstCustomer.end(); it++){
		//循环对象结构中的元素,接受访问
		pCustomer = (*it); pCustomer->Accept(&oPredilectionAnalyzeVisitor);
	}

	cout << "Before Deleting... size : " << lstCustomer.size() << endl;
	for(list<CCustomer*>::iterator it = lstCustomer.begin(); it != lstCustomer.end(); ){
		//循环对象结构中的元素,接受访问
		pCustomer = (*it); delete pCustomer;
		it = lstCustomer.erase(it);
	}
	cout << "After Deleted... size : " << lstCustomer.size() << endl;
}


/*输出结果:
ABC集团企业提出服务请求
CDE集团企业提出服务请求
客户张三提出服务请求
现在对企业客户ABC集团进行产品偏好分析
现在对企业客户CDE集团进行产品偏好分析
现在对个人客户张三进行产品偏好分析
*/

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值