設計模式應用之使用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; } } //---------------------------------------------------------------