設計模式應用之使用COMPOSITE模式實現流程(四)

                     設計模式應用之使用COMPOSITE模式實現流程(四)

   最近在工作的過程中,完成了一個實現動態流程的任務。因此將我的demo程序共享出來,給大家參考如何使用COMPOSITE實現流程的編寫。在前面序列文章,我本來計劃利用MEMENTO 解耦COMPOSITE 對象,使COMPOSITE 對象得到共用,但是在實際開發過程中,我發現這樣在開發上有一定的難度,因此我沒有采用這樣的思路去開發。

  語音流程抽象起來包括:播放語音、播放菜單、還有其他葉子操作。因此語音流程的每個用戶的每一選擇,就構成了一棵狀態子樹。而這樣的狀態子樹,如果採用常規的子樹的遍歷,這樣的指針指向會指向很多層。因此我在實際開發過程中,抽象出一個TRootComposit 對象。具體的就不詳細介紹了,我把不涉及到機密的東東,當作一個demo拿出來給大家參考。

   以下是頭文件:

#ifndef __COMPOMENT__H__
#define __COMPOMENT__H__
//-------------------------------------------------------------------------------------------------------------
#include <string>
#include <map>
#include <vector>
using namespace Unify;
//-------------------------------------------------------------------------------------------------------------
#define HANDLE_NEXT 	1  //獲取下一個節點(主要是composite對象)
#define HANDLE_PRE  	2  //獲取上一個節點(主要是composite對象)
#define HANDLE_END  	3  //某一個流程分支都處理完
#define HANDLE_ERROR	4  //節點執行的操作有誤
#define HANDLE_ERROR_NOTIFY 5 //節點執行錯誤,有提示
#define HANDLE_SELF   6  //駐留在節點執行
#define HANDLE_DEF    7  //默認的錯誤
//-------------------------------------------------------------------------------------------------------------
class IvrCompoment
{
public:
	IvrCompoment();
	virtual ~IvrCompoment();
	//節點處理事件
	virtual int handle(TIvrCallSessionInfo& s,const TIvrAppEventInfo& e);
	//獲取孩子節點
	virtual IvrCompoment* getChild(const std::string& cond);
	//這個接口是判斷是否是composit對象
	virtual IvrCompoment* getComposite();
	//用於返回上一級目錄
	virtual IvrCompoment* getPreCompoment();
	//判斷是否本compoment對象
	virtual bool equal(const std::string& cond);
	//添加孩子節點,只要是composit對象
	virtual void addChild(IvrCompoment* child);	
	//遞歸構建樹,可能要傳入孩子信息
	virtual void buildChild(DbServer::TRecordSetSeq& sRec);
	//設置本節點信息
	virtual void set(DbServer::TRecordSet& rec);
	virtual void reset();
};
//-------------------------------------------------------------------------------------------------------------
class IvrVoiceLeaf:public IvrCompoment
{
public:
	IvrVoiceLeaf();
	~IvrVoiceLeaf();
	virtual int handle(TIvrCallSessionInfo& s,const TIvrAppEventInfo& e);
	virtual bool equal(const std::string& cond);
	virtual void set(DbServer::TRecordSet& rec);
private:
	std::string	_actid;
	std::string	_preid;
	std::string _condtion;
	std::string _actname;
	std::string	_record;
	std::string _ttstext;
	std::string _recordfile;
	int			_step;
};
//-------------------------------------------------------------------------------------------------------------
class IvrComposite:public IvrCompoment
{
public:
	IvrComposite(IvrCompoment* ivr);
	virtual ~IvrComposite();
	virtual int handle(TIvrCallSessionInfo& s,const TIvrAppEventInfo& e);
	//獲取孩子節點
	virtual IvrCompoment* getChild(const std::string& cond);
	//這個接口是判斷是否是composit對象
	virtual IvrCompoment* getComposite();
	//用於返回上一級目錄
	virtual IvrCompoment* getPreCompoment();
	//判斷是否本compoment對象
	virtual bool equal(const std::string& cond);
	//添加孩子節點,只要是composit對象
	virtual void addChild(IvrCompoment* child);	
	//遞歸構建樹,可能要傳入孩子信息
	virtual void buildChild(DbServer::TRecordSetSeq& sRec);
	//設置本節點信息
	virtual void set(DbServer::TRecordSet& rec);
private:
	// 0 go to child,1 not
	bool CheckCond(const std::string& cond);
	std::string	_actid;
	std::string	_preid;
	std::string _condtion;
	std::string _actname;
	std::string	_record;
	std::string _ttstext;
	std::string _recordfile;
	int			_step;
	std::vector<IvrCompoment*> _childs;
	IvrCompoment* _preIvr;
};
//-------------------------------------------------------------------------------------------------------------
class TRootComposit:public IvrCompoment
{
public:
	TRootComposit();
	~TRootComposit();
	virtual int handle(TIvrCallSessionInfo& s,const TIvrAppEventInfo& e);
	virtual void buildChild(DbServer::TRecordSetSeq& sRec);	
	virtual void reset();
	//這個接口是判斷是否是composit對象
	virtual IvrCompoment* getComposite(){return this;}
private:
	IvrCompoment* _root;
	IvrCompoment* _subRoot;//由於composit對象可能是一棵樹
						   //_subRoot 指向下一個子樹	
};
//-------------------------------------------------------------------------------------------------------------
class IvrMannage
{
public:
	~IvrMannage();
	int ReSetRoot(const std::string& key);
	int BuilderSessIvr(TIvrCallSessionInfo& s);
	int Handle(TIvrCallSessionInfo& s,const TIvrAppEventInfo& e);
	int DeleteSessIvr(TIvrCallSessionInfo& s);
	static IvrMannage* instance();
private:
	IceUtil::RecMutex  _mutex;
	IvrMannage();
	static IvrMannage* _instance;
	std::map<std::string,IvrCompoment*> _ivrMap;
};
//-------------------------------------------------------------------------------------------------------------
#endif



#include "Compoment.h"
const int ErrorPlayLast = 90000;
const int TopFlow       = 1000;
const int InToFlow      = 2202;
const int SelfFlow      = 2101;
const int QUITFlow      = 94000;

//---------------------------------------------------------------
//IvrMannage
//---------------------------------------------------------------
IvrMannage* IvrMannage::_instance = NULL;
IvrMannage* IvrMannage::instance()
{
	if(_instance == NULL)
	{
		_instance = new IvrMannage();
	}
	return _instance;
}
//---------------------------------------------------------------
IvrMannage::IvrMannage()
{
	;
}
//---------------------------------------------------------------
IvrMannage::~IvrMannage()
{
}
//---------------------------------------------------------------
int IvrMannage::BuilderSessIvr(TIvrCallSessionInfo& s)
{
	if(_ivrMap.find(s.SessionId) != _ivrMap.end())
		return -1;
	DbServer::TRecordSetSeq selfInfo;
	int res = getAct(s,selfInfo);//獲取某一個id的動態流程信心。
	if(res <= 0)
	{
		return -1;
	}
	//find for root act
	unsigned int idx = 0;
	for(idx; idx < selfInfo.size();idx++)
	{
		disp_msg(2,"preid = [%s]",selfInfo[idx][2].c_str());
		if(selfInfo[idx][2] == "-1")
		{
			break;
		}
	}

	if(idx >= selfInfo.size() || selfInfo.empty())
	{
		disp_msg(2,"Enid =[%d] does not have Root Act",s.entid);
		return -1;
	}
	IvrCompoment* root;
	if(selfInfo.size() != 1)
	{
		root = new TRootComposit();
	}
	else
	{
		root = new IvrVoiceLeaf();
	}

	if(root == NULL)
	{
		disp_msg(2,"Enid =[%d] does new Act Error",s.entid);
		return -1;
	}
	root->buildChild(selfInfo);
	RecMutex::Lock lock(_mutex);
	_ivrMap.insert(std::make_pair(s.SessionId,root));
	return 0;
}
//---------------------------------------------------------------
int IvrMannage::ReSetRoot(const std::string &key)
{
	IceUtil::RecMutex::Lock lock(_mutex);
	std::map<std::string,IvrCompoment*>::iterator it;
	it = _ivrMap.find(key);
	if(it != _ivrMap.end())
	{
		it->second->reset();
		return 0;
	}
	return -1;
}
//---------------------------------------------------------------
int IvrMannage::DeleteSessIvr(TIvrCallSessionInfo& s)
{
	RecMutex::Lock lock(_mutex);
	std::map<std::string,IvrCompoment*>::iterator it;
	it = _ivrMap.find(s.SessionId);
	if(it != _ivrMap.end())
	{
		delete it->second;
		it->second = NULL;
		_ivrMap.erase(it);
	}
	return 0;
}
//---------------------------------------------------------------
//class IvrCompoment
//---------------------------------------------------------------
IvrCompoment::IvrCompoment()
{
}
//---------------------------------------------------------------
IvrCompoment::~IvrCompoment()
{
}
//---------------------------------------------------------------
void IvrCompoment::addChild(IvrCompoment*)
{
}
//---------------------------------------------------------------
int IvrCompoment::handle(TIvrCallSessionInfo& s,const TIvrAppEventInfo& e)
{
	return 0;
}
//---------------------------------------------------------------
IvrCompoment* IvrCompoment::getChild(const std::string& cond)
{
	return 0;
}
//---------------------------------------------------------------
IvrCompoment* IvrCompoment::getComposite()
{
	return 0;
}
//---------------------------------------------------------------
IvrCompoment* IvrCompoment::getPreCompoment()
{
	return 0;
}
//---------------------------------------------------------------
bool IvrCompoment::equal(const std::string& cond)
{
	return true;
}
//---------------------------------------------------------------
void IvrCompoment::buildChild(DbServer::TRecordSetSeq& sRec)
{
}
//---------------------------------------------------------------
void IvrCompoment::set(DbServer::TRecordSet& rec)
{
}
//---------------------------------------------------------------
void IvrCompoment::reset()
{
}
//---------------------------------------------------------------
//class IvrVoiceLeaf
//---------------------------------------------------------------
IvrVoiceLeaf::IvrVoiceLeaf()
{
	_step = 0;
}
//---------------------------------------------------------------
IvrVoiceLeaf::~IvrVoiceLeaf()
{
	;
}
//---------------------------------------------------------------
bool IvrVoiceLeaf::equal(const std::string& cond)
{
	return (_condtion == cond);
}
//---------------------------------------------------------------
void IvrVoiceLeaf::set(DbServer::TRecordSet& rec)
{
/*
	os<<"select actid,acttype,preid,"
	  <<"condtion,actname,record,ttstext,recordfile from amrx_act"
	  <<" where state = 0 and entid="<<sInfo.entid
	  <<" order by preid";
*/
	_actid = rec[0];
	_preid = rec[2];
	_condtion = rec[3];
	_actname = rec[4];
	_record = rec[5];
	_ttstext = rec[6];
	_recordfile = rec[7];
}
//---------------------------------------------------------------
int IvrVoiceLeaf::handle(TIvrCallSessionInfo& s,const TIvrAppEventInfo& e)
{
	int v;
	bool b = false;
	while(!b)
	{
		disp_msg(3,"IvrVoiceLeaf:name = [%s],cond = [%s],step = [%d]",
		     _actname.c_str(),_condtion.c_str(),_step);
		switch(_step)
		{
		case 0:
			if(_record == "1" && !_recordfile.empty())
			{
				s.VoiceFile = _recordfile;
				setCallSession(s);//保存當前的信息
				_step = 3;
			}
			else
			{//alloc tts
				allocTts(s.SessionId,1);
				b = true;
				_step = 1;
			}
			v = HANDLE_SELF;
			break;
		case 1:
			if(e.UCEventInfo.EventType == UCEventEndCall ||
				e.UCEventInfo.ResCode != 0)
			{
				v = HANDLE_ERROR;
			}
			else
			{//tts change
				v = HANDLE_SELF;
				_step = 2;
				if(ttsChange(s.SessionId,_ttstext))
				{
					v = HANDLE_ERROR;
				}
			}
			b = true;
			break;
		case 2:
			if(e.UCEventInfo.EventType == UCEventEndCall ||
				e.UCEventInfo.ResCode != 0)
			{
				v = HANDLE_ERROR;
				b = true;
			}
			else
			{
				s.VoiceFile = e.UCEventInfo.TtsFileName;
				setCallSession(s);
				_step = 3;
			}
			break;
		case 3:
			v = HANDLE_SELF;
			b = true;
			_step = 4;
			if(playFileDtmf(s.SessionId,s.VoiceFile,1,0,5000))
			{
				v = HANDLE_ERROR;
			}
			break;
		case 4:
			b = true;
			if(e.UCEventInfo.EventType == UCEventEndCall ||
				e.UCEventInfo.ResCode != 0)
			{
				v = HANDLE_ERROR;
			}
			else
			{
				setSessionErrorCounts(s.SessionId,0);
				s.smstxt = _ttstext;
				setCallSession(s);
				v = HANDLE_END;
			}
			break;
		default:
			b = true;
			break;
			v = HANDLE_ERROR;
		}
	}
	if(v != HANDLE_SELF)
		_step = 0;
	return v;
}
//---------------------------------------------------------------
//IvrComposite
//---------------------------------------------------------------
IvrComposite::IvrComposite(IvrCompoment* ivr):
_preIvr(ivr),
_step(0)
{
}
//---------------------------------------------------------------
IvrComposite::~IvrComposite()
{
	for(unsigned int i = 0; i < _childs.size();i++)
		delete _childs[i];
}
//---------------------------------------------------------------
IvrCompoment* IvrComposite::getChild(const std::string& cond)
{
	IvrCompoment* ivr = 0;
	for(unsigned int i = 0; i < _childs.size();i++)
	{
		if(_childs[i] !=0 && _childs[i]->equal(cond))
		{
			ivr = _childs[i];
			break;
		}
	}
	return ivr;
}
//---------------------------------------------------------------
IvrCompoment* IvrComposite::getComposite()
{
	return this;
}
//---------------------------------------------------------------
IvrCompoment* IvrComposite::getPreCompoment()
{
	return _preIvr;
}
//---------------------------------------------------------------
bool IvrComposite::equal(const std::string& cond)
{
	return (_condtion == cond);
}
//---------------------------------------------------------------
void IvrComposite::addChild(IvrCompoment* child)
{
	if(child != 0)
		_childs.push_back(child);
}
//---------------------------------------------------------------
void IvrComposite::set(DbServer::TRecordSet& rec)
{
	_actid = rec[0];
	_preid = rec[2];
	_condtion = rec[3];
	_actname = rec[4];
	_record = rec[5];
	_ttstext = rec[6];
	_recordfile = rec[7];
}
//---------------------------------------------------------------
void IvrComposite::buildChild(DbServer::TRecordSetSeq& sRec)
{//遞歸構建該節點的子樹
	IvrCompoment* ivr;
	for(unsigned int i = 0; i < sRec.size();i++)
	{
		unsigned int j = 0;
		if(_actid == sRec[i][2])
		{//找到該節點的子節點
			for(j = 0; j < sRec.size();j++)
			{//判斷是否是複合動作
				if(sRec[i][0] == sRec[j][2])
					break;
			}
			if(j < sRec.size())
			{//是composite對象
				ivr = new IvrComposite(this);
			}
			else
			{//Leaf object
				ivr = new IvrVoiceLeaf();
			}
			if(ivr != 0)
			{
				ivr->set(sRec[i]);
				ivr->buildChild(sRec);
				addChild(ivr);
			}
		}//end if
	}//end for
}
//---------------------------------------------------------------
bool IvrComposite::CheckCond(const std::string& cond)
{
	bool b = false;
	for(unsigned int i = 0; i < _childs.size(); i++)
	{
		if(_childs[i] != 0 && _childs[i]->equal(cond))
		{
			b = true;
			break;
		}
	}
	return b;
}
//---------------------------------------------------------------
int IvrComposite::handle(TIvrCallSessionInfo& s,const TIvrAppEventInfo& e)
{
	int v;
	bool b = false;
	std::string file;
	while(!b)
	{
		disp_msg(3,"IvrComposite:name = [%s],cond = [%s],step = [%d]",
				 _actname.c_str(),_condtion.c_str(),_step);
		switch(_step)
		{//0 tts 1 file
		case 0:
			if(_record == "1" && !_recordfile.empty())
			{
				s.VoiceFile = _recordfile;
				file = s.VoiceFile;
				gReSourcePool->setCallSession(s);
				_step = 3;
			}
			else
			{//alloc tts
				allocTts(s.SessionId,1);
				b = true;
				_step = 1;
			}
			v = HANDLE_SELF;
			break;
		case 1:
			if(e.UCEventInfo.EventType == UCEventEndCall ||
				e.UCEventInfo.ResCode != 0)
			{
				v = HANDLE_ERROR;
			}
			else
			{//tts change
				v = HANDLE_SELF;
				_step = 2;
				if(ttsChange(s.SessionId,_ttstext))
				{
					v = HANDLE_ERROR;
				}
			}
			b = true;
			break;
		case 2:
			if(e.UCEventInfo.EventType == UCEventEndCall ||
				e.UCEventInfo.ResCode != 0)
			{
				v = HANDLE_ERROR;
				b = true;
			}
			else
			{
				s.VoiceFile = e.UCEventInfo.TtsFileName;
				file        = s.VoiceFile;
				gReSourcePool->setCallSession(s);
				_step = 3;
			}
			break;
		case 3:
			v = HANDLE_SELF;
			b = true;
			if(playFileDtmf(s.SessionId,file,1,0,5000))
			{
				v = HANDLE_ERROR;
			}
			_step = 4;
			break;
		case 4:
			if(e.UCEventInfo.EventType == UCEventEndCall ||
				e.UCEventInfo.ResCode != 0)
			{
				v = HANDLE_ERROR;
				b = true;
			}
			else
			{
				if(e.UCEventInfo.Dtmf[0] =='*')
				{
					v = HANDLE_PRE;
					b = true;
				}
				else
				{
					if(CheckCond(e.UCEventInfo.Dtmf))
					{
						v = HANDLE_NEXT;
						b = true;
						setSessionErrorCounts(s.SessionId,0);
					}
					else
					{//出錯
						if(addSessionErrorCounts(s.SessionId)<= gMaxErrCounts)
						{
							file = "amrx//errin;"+s.VoiceFile;
							_step = 3;
						}
						else
						{
							b = true;
							v = HANDLE_ERROR_NOTIFY;
							s.VoiceFile = "amrx//maxerr";
							setCallSession(s);
						}
					}
				}
			}
			break;
		default:
			_step = 5;
			b = true;
			v = HANDLE_ERROR;
			break;
		}//end switch
	}
	if(v != HANDLE_SELF)
		_step = 0;
	return v;
}
//---------------------------------------------------------------
//TRootComposit
//---------------------------------------------------------------
TRootComposit::TRootComposit():
_root(0),
_subRoot(0)
{
}
//---------------------------------------------------------------
TRootComposit::~TRootComposit()
{
	delete _root;
}
//---------------------------------------------------------------
void TRootComposit::reset()
{
	_subRoot = _root;
}
//---------------------------------------------------------------
void TRootComposit::buildChild(DbServer::TRecordSetSeq& sRec)
{
	unsigned int idx = 0;
	for(idx; idx < sRec.size();idx++)
	{
		disp_msg(2,"preid = [%s]",sRec[idx][2].c_str());
		if(sRec[idx][2] == "-1")
		{
			break;
		}
	}

	if(idx >= sRec.size())
	{
		disp_msg(2,"TRootComposit build child Error = [no root act]");
		return;
	}
	_root = new IvrComposite(0);
	if(_root != 0)
	{
		_root->set(sRec[idx]);
		_root->buildChild(sRec);
		_subRoot = _root;
	}
}
//---------------------------------------------------------------
int TRootComposit::handle(TIvrCallSessionInfo& s,const TIvrAppEventInfo& e)
{
/*
#define HANDLE_NEXT 	1  //獲取下一個節點(主要是composite對象)
#define HANDLE_PRE  	2  //獲取上一個節點(主要是composite對象)
#define HANDLE_END  	3  //某一個流程分支都處理完
#define HANDLE_ERROR	4  //節點執行的操作有誤
#define HANDLE_ERROR_NOTIFY 5 //節點執行錯誤,有提示
#define HANDLE_SELF   6  //駐留在節點執行
*/
	int v = HANDLE_ERROR;
	bool top = false;
	while(true)
	{
		v = HANDLE_DEF;
		if(_subRoot != 0)
			v = _subRoot->handle(s,e);
		switch(v)
		{
		case HANDLE_NEXT:
			 _subRoot = _subRoot->getChild(e.UCEventInfo.Dtmf);
			 break;
		case HANDLE_PRE:
			top = (_subRoot == _root);
			_subRoot  = _subRoot->getPreCompoment();
			if( top && _subRoot == 0)
			{
				_subRoot = _root;
				return TopFlow;
			}
			break;
		case HANDLE_END:
			//該流程的某個子樹已經處理完了,返回到匯聚點
			disp_msg(3,"TRootComposit 3 InToFlow=[%d]",InToFlow);
			return InToFlow;
		case HANDLE_ERROR:
			disp_msg(3,"TRootComposit 4 QUITFlow=[%d]",QUITFlow);
			return QUITFlow;
		case HANDLE_ERROR_NOTIFY:
			disp_msg(3,"TRootComposit 5 ErrorPlayLast=[%d]",ErrorPlayLast);
			return ErrorPlayLast;
		case HANDLE_SELF:
			disp_msg(3,"TRootComposit 6 SelfFlow=[%d]",SelfFlow);
			return SelfFlow;
		default:
			disp_msg(3,"TRootComposit 7 QUITFlow=[%d]",QUITFlow);
			return QUITFlow;
		}//end switch
	}
}
//---------------------------------------------------------------
int IvrMannage::Handle(TIvrCallSessionInfo& s,const TIvrAppEventInfo& e)
{
	std::map<std::string,IvrCompoment*>::iterator it;
	IvrCompoment* root = 0;
	{
		IceUtil::RecMutex::Lock lock(_mutex);
		it = _ivrMap.find(s.SessionId);
		if(it != _ivrMap.end())
			root = it->second;
		if(root == 0)
			return QUITFlow;
	}
	int v = QUITFlow;
	if(root->getComposite() == 0)
	{
		int v = root->handle(s,e);
		switch(v)
		{
		case HANDLE_END:
			v = InToFlow;
			break;
		case HANDLE_SELF:
			v = SelfFlow;
			break;
		default:
			v = QUITFlow;
			break;
		}//end if
		disp_msg(3,"IvrMannage::Handle Leaf return v =[%d]",v);
		return v;
	}
	else
	{
		v = root->handle(s,e);
		disp_msg(3,"IvrMannage::Handle RootComposit return v =[%d]",v);
		return v;
	}
}
//---------------------------------------------------------------


發佈了49 篇原創文章 · 獲贊 24 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章