流程组装配置列表
组件化的优点:
a)将流程和被流程调用的子模块进行解耦。例如:批价函数,m_pPriceGuiding->ExecuteRating();在现有的在线流程中共有38处地方进行了调用,而按新的设计方案只会在一个组件(ExecuteRating)中进行调用,要用的批价的地方,只要将其加到流程组装配置列表即可。可以想象,如果ExecuteRating()函数接口改变了,对于原有的在线流程将会是一个灾难,而新的设计将可以轻松应对。注意:这并不是一个特例,在流程中几乎所有对子模块的调用都存在这种情况。
b)组件的复用和移植。新的设计改变了原来以整个流程为最小单位的方式,而是一个组件为系统的最小单位。每个组件都是功能独立的,互不影响的方法集。不仅可以在不同流程间进行复用,甚至于可以跨版本地复用。包括组件移植时,成本也是很低的,只要将组件的代码文件进行移植即可,移植的是文件而不是代码。
c)一些组件会趋于稳定。原来以流程为最小单位设计,任何的改变都会影响到整个流程,导致每次升版时流程的代码总是有很大的变化。而新的设计以组件为系统最小的单位,有一些组件会趋于稳定,一定程度上保持不变。从而分隔了系统中变化和不变的部分。使系统从整体上更加健壮。
下面介绍一些代码的细节。
RatingCtrlComponent.h
#ifndef RATINGCTRLCOMPONENT_H_
#define RATINGCTRLCOMPONENT_H_
class RatingCtrlComponent
{
public:
virtual ~RatingCtrlComponent()
{
}
/**
* @brief 组件流程执行接口
*
* @param pRatableEvent [in/out]
* @return bool
*/
virtual bool Execute(TRatableEvent& pRatableEvent) = 0;
};
#endif
RatingCtrlDectorator .h
#ifndef RATINGCTRLDECTORATOR_H_
#define RATINGCTRLDECTORATOR_H_
#include "RatingCtrlComponent.h"
class RatingCtrlDectorator : public RatingCtrlComponent
{
public:
RatingCtrlDectorator(RatingCtrlComponent* pComponentA) : m_pComponentA(pComponentA)
{
}
virtual ~RatingCtrlDectorator()
{
}
/**
* @brief 组件流程执行接口
*
* @param pRatableEvent [in/out]
* @return bool
*/
virtual bool Execute(TRatableEvent& pRatableEvent) = 0;
protected:
RatingCtrlComponent* m_pComponentA; ///< 该组件的下一个组件(A分支)
};
#endif
ComponentFactory.h
#ifndef COMPONENTFACTORY_H_
#define COMPONENTFACTORY_H_
#include <list>
#include <vector>
#include "ComponentDefine.h"
#include "RatingCtrlComponent.h"
class ComponentFactory
{
public:
ComponentFactory()
{
}
virtual ~ComponentFactory()
{
ClearComponent();
}
/**
* @brief 装配组件
*
* 根据编码[一个数组]装配组件。
* 将各个组件构成一个流程分支链表。
*
* @param viComponentID [in]
* @return RatingCtrlComponent 流程的头结点
*/
RatingCtrlComponent* BuildComponent(vector<int>& viComponentID);
void ClearComponent();
protected:
virtual RatingCtrlComponent* CreateComponent(int iComponentID, RatingCtrlComponent* pComponent,
list<RatingCtrlComponent*>& lpComponent) = 0;
private:
list<RatingCtrlComponent*> m_lpComponent;
vector<RatingCtrlComponent*> m_vpComponent;
};
#endif
ComponentFactory.cpp
#include "ComponentFactory.h"
void ComponentFactory::ClearComponent()
{
vector<RatingCtrlComponent*>::iterator itr;
for (itr = m_vpComponent.begin(); itr != m_vpComponent.end(); ++itr)
{
delete * itr;
*itr = NULL;
}
}
/*
下面的代码很短,却完了一件精妙的工作.组件以一种近似网状的结构组织起来,
就像所有的网络流算法一样,程序的执行过程就是选择一条路径遍历的过程.
不同的是这边的分支是根据业务不同的而进行选择的。如此复杂的想法却以
这么简单的方式来实现,甚为精妙!-----by liang.shishi
*/
RatingCtrlComponent* ComponentFactory::BuildComponent(vector<int>& viComponentID)
{
if (viComponentID.empty())
return NULL;
m_lpComponent.clear();
RatingCtrlComponent* pComponent = NULL;
vector<int>::iterator itr = viComponentID.end() - 1;
// 增加默认基础类
if (*itr != NONE_COMPONENT)
{
viComponentID.push_back(NONE_COMPONENT);
}
for (itr = viComponentID.end() - 1; itr >= viComponentID.begin(); --itr)
{
if (*itr < 0)
{
if (*itr == -1)
{
// 正常分支结束后,放在容器后面
m_lpComponent.push_back(pComponent);
}
else
{
for (int i = 0; i < (*itr)*(-1); i++)
{
// 多分支情况,放容器前面
m_lpComponent.push_front(pComponent);
}
}
// 处理以0结束的分支
if ((itr - 1) >= viComponentID.begin() && *(itr - 1) == 0)
{
pComponent = NULL;
}
else
{
pComponent = m_lpComponent.front();
m_lpComponent.pop_front();
}
continue;
}
pComponent = CreateComponent(*itr, pComponent, m_lpComponent);
// 组装失败
if (pComponent == NULL)
{
ClearComponent();
// LOG
return NULL;
}
m_vpComponent.push_back(pComponent);
}
return pComponent;
}
RatingCtrlFactory .h
#ifndef RATINGCTRLFACTORY_H_
#define RATINGCTRLFACTORY_H_
#include "ComponentFactory.h"
class RatingCtrlFactory : public ComponentFactory
{
public:
/**
* @brief 创建组件
*
* 根据iComponentID创建对应的组件,用pComponent初始化新组件,最后返回新组件给pComponent。
* 对于分支组件,需要根据lpComponent做特殊处理~
*
* @param iComponentID [in]
* @param pComponent [in/out]
* @param lpComponent [in/out]
*/
virtual RatingCtrlComponent* CreateComponent(int iComponentID, RatingCtrlComponent* pComponent,
list<RatingCtrlComponent*>& lpComponent);
private:
RatingCtrlComponent* Back(list<RatingCtrlComponent*>& lpComponent);
};
#endif
#include "RatingCtrlFactory.h"
#include "NoneComponent.h"
RatingCtrlComponent* RatingCtrlFactory::Back(list<RatingCtrlComponent*>& lpComponent)
{
RatingCtrlComponent* pComponent = lpComponent.back();
lpComponent.pop_back();
return pComponent;
}
// 当遇到多分支的时候,应该先将pComponent放回链表首,再从链表尾取出相应数量的组件指针进行组装.
RatingCtrlComponent* RatingCtrlFactory::CreateComponent(int iComponentID, RatingCtrlComponent* pComponent,
list<RatingCtrlComponent*>& lpComponent)
{
ADD_TRACE("%s RatingCtrlFactory::CreateComponent IN: iComponentID: %d, pComponent: %p.
", LOG_PREFIX, iComponentID,
pComponent);
if (iComponentID != NONE_COMPONENT && pComponent == NULL)
{
ADD_TRACE("%s RatingCtrlFactory::CreateComponent OUT: iComponentID: %d, pComponent: %p.
", LOG_PREFIX, iComponentID,
pComponent);
return NULL;
}
switch (iComponentID)
{
case NONE_COMPONENT:
{
if (pComponent != NULL)
{
return NULL;
}
pComponent = new NoneComponent();
break;
}
case EXECUTE_INITIALIZE:
{
pComponent = new ExecuteInitialize(pComponent);
break;
}
case EXECUTE_PROCESS_IN:
{
lpComponent.push_front(pComponent);
if (lpComponent.size() < 4)
{
return NULL;
}
pComponent = new ExecuteProcessIN(Back(lpComponent), Back(lpComponent), Back(lpComponent), Back(lpComponent));
break;
}
default:
{
return NULL;
}
}
return pComponent;
}
复杂分机的代码实现:
#ifndef EXECUTEPROCESSIN_H_
#define EXECUTEPROCESSIN_H_
#include "RatingCtrlDectorator.h"
class ExecuteProcessIN : public RatingCtrlDectorator
{
public:
ExecuteProcessIN(RatingCtrlComponent* pComponentA, RatingCtrlComponent* pComponentB, RatingCtrlComponent* pComponentC,
RatingCtrlComponent* pComponentD) : RatingCtrlDectorator(pComponentA), m_pComponentB(pComponentB),
m_pComponentC(pComponentC), m_pComponentD(pComponentD)
{
}
virtual ~ExecuteProcessIN()
{
}
/**
* @brief IN业务流程选择
*
* 根据 ExecuteId 选择流程
* A:初始包流程; B:更新包流程; C:结束包鉴权; D:异常流程
*
* @param pRatableEvent [in]
* @return bool
*/
virtual bool Execute(TRatableEvent& pRatableEvent);
private:
RatingCtrlComponent* m_pComponentB;
RatingCtrlComponent* m_pComponentC;
RatingCtrlComponent* m_pComponentD;
};
#endif
#include "ExecuteProcessIN.h"
bool ExecuteProcessIN::Execute(TRatableEvent& pRatableEvent)
{
ADD_TRACE("%s ExecuteProcessIN::Execute() Begin.
", LOG_PREFIX);
int iExecuteId = pRatableEvent.GetAttrEx(EA::EXECUTE_ID)->AsInteger();
switch (iExecuteId)
{
case EXECUTE_ID_INIT:
{
ADD_TRACE("%s ExecuteProcessIN::Execute() End Goto EXECUTE_ID_INIT Process.
", LOG_PREFIX);
return m_pComponentA->Execute(pRatableEvent);
}
case EXECUTE_ID_UPDATE:
{
ADD_TRACE("%s ExecuteProcessIN::Execute() End Goto EXECUTE_ID_UPDATE Process.
", LOG_PREFIX);
return m_pComponentB->Execute(pRatableEvent);
}
case EXECUTE_ID_FINISH:
{
ADD_TRACE("%s ExecuteProcessIN::Execute() End Goto EXECUTE_ID_FINISH Process.
", LOG_PREFIX);
return m_pComponentC->Execute(pRatableEvent);
}
case EXECUTE_ID_EMCDR:
{
ADD_TRACE("%s ExecuteProcessIN::Execute() End Goto EXECUTE_ID_EMCDR Process.
", LOG_PREFIX);
return m_pComponentD->Execute(pRatableEvent);
}
default:
{
pRatableEvent.SetAttr(EA::OCS_RESULT_CODE, CCA::DIAMETER_RATING_FAILED);
ADD_ERROR("ZSmart-Charging-Online-1015",
"%s ExecuteProcessIN::ExecuteRatableEvent() GetExecuteId Failed. iExecuteId = [%d], ReturnCode = [%d]
",
LOG_PREFIX, iExecuteId, pRatableEvent.GetAttrEx(EA::OCS_RESULT_CODE)->AsInteger());
}
}
ADD_TRACE("%s ExecuteProcessIN::Execute() Fail.
", LOG_PREFIX);
return false;
}
最终复杂的流程图: