目录
职责链模式定义
职责链模式,是一种行为型模式,使多个对象构成对象链,将一个请求传递给对象链,哪个对象适合处理这个请求就让哪个对象来处理,可避免请求的发送者和接收者之间的耦合关系。
如果请求在对象链上节点处理后仍可以往下传递,这种每个节点只处理一部分的职责链即是功能链,类似于流水线每个站点只处理任务的一部分,到流水线尽头任务即完成。
职责链模式的优点
- 减少请求的发送者和接收者之间的耦合:发送者和接收者不需要知道彼此的具体细节。
- 增强了系统的灵活性:可以动态地添加或修改处理链,而不影响其他部分。
- 增强了给定请求的处理机会:请求可以被多个对象处理,不必绑定到特定的处理者。
职责链模式的缺点
- 请求可能未被处理:如果链配置不当,请求可能会到达链的末端而未被处理。
- 性能问题:在某些情况下,由于需要在链上进行多次处理判断,可能会引入性能瓶颈。
- 调试困难:由于处理过程的动态性,可能难以跟踪请求在链中的传递路径。
职责链模式的适用场景
- 多个对象可以处理同一请求:当多个对象都可能对请求进行处理,但具体由哪个对象处理在运行时才确定时,职责链模式提供了一种灵活的处理方式。
- 不明确具体接收者:在请求的发送者不需要知道请求的具体接收者是谁的情况下,使用职责链模式可以将发送者和接收者解耦。
- 可动态指定处理的顺序:当需要在运行时动态改变请求处理者的顺序或者动态添加新的处理者时,职责链模式能够提供这种灵活性。
请假处理职责链代码举例
请假流程根据请假的类型时长等需要不同级别的leader处理,以职责链的形式将不同级别的leader对象从低到高连接,所有的请假任务可以从职责链从头开始处理,最终会在职责链某处会处理掉。
//请假请求类
class AskOffRequest
{
public:
//构造函数
AskOffRequest(const string& name, int nDays) :m_nameStr(name), m_nDays(nDays) {}
//获取请假的人员名字
const string& getName() const
{
return m_nameStr;
}
//获取请假天数和类型
int getOffDays() const
{
return m_nDays;
}
private:
string m_nameStr; //人员名称
int m_nDays; //请假天数
};
//管理员类
class HrManager
{
public:
HrManager() :m_nextChain(nullptr) {}
virtual ~HrManager() {} //做父类时析构函数应该为虚函数
//设置指向的职责链中的下个审批者
void setNextChain(shared_ptr<HrManager> next)
{
m_nextChain = next;
}
//请求处理
virtual void processRequest(const AskOffRequest& req) = 0;
protected:
//找链中的下个对象并把请求投递给下个链中的对象
void sendRequestToNextHandler(const AskOffRequest& req)
{
//找链中的下个对象
if (m_nextChain != nullptr)
{
//把请求投递给链中的下个对象
m_nextChain->processRequest(req);
}
}
private:
shared_ptr<HrManager> m_nextChain;
};
//具体有权限处理请假的管理员
class TeamLeader:public HrManager
{
public:
void processRequest(const AskOffRequest& req) override
{
if (req.getOffDays <= 2)
{
cout << req.getName << "请假" << req.getOffDays() << "天,通过!" << endl;
}
else
{
sendRequestToNextHandler(req);
}
}
};
class DeparmentLeader :public HrManager
{
public:
void processRequest(const AskOffRequest& req) override
{
if (req.getOffDays <= 7)
{
cout << req.getName << "请假" << req.getOffDays() << "天,通过!" << endl;
}
else
{
sendRequestToNextHandler(req);
}
}
};
class CompanyLeader :public HrManager
{
public:
void processRequest(const AskOffRequest& req) override
{
if (req.getOffDays <= 30)
{
cout << req.getName << "请假" << req.getOffDays() << "天,通过!" << endl;
}
else
{
cout << req.getName << "请假" << req.getOffDays() << "天,需要当面沟通!" << endl;
}
}
};
//测试职责链
int testChain()
{
auto pLeader1 = make_shared<TeamLeader>( new TeamLeader());
auto pLeader2 = make_shared<TeamLeader>(new DeparmentLeader());
auto pLeader3 = make_shared<TeamLeader>(new CompanyLeader());
pLeader1->setNextChain(pLeader2);
pLeader2->setNextChain(pLeader3);
AskOffRequest task1("zhangsan", 20);
AskOffRequest task2("lisi", 2);
AskOffRequest task3("wangwu", 10);
pLeader1->processRequest(task1);
pLeader1->processRequest(task2);
pLeader1->processRequest(task3);
}
项目问题背景
车辆在出场付费放行时候可能有多种付款方式支持,如ETC支付,平台无感代扣,车主扫码支付,刷卡支付,现金支付等等;对于现金、刷卡和车主扫码支付由车主参与因此不会有竞态和优先级问题。但是对于ETC和平台代扣出场由于都是无感出场会导致出现竞态容易重复扣费,且优先级各个车厂要求不一样。
解决方案
对于各种无感支付之间的优先级以及重复扣费风险可以采用职责链模式进行扣款逻辑优化,从而避免无感支付之间的重复扣费风险,以及优先级可根据车厂要求设置。
无感支付职责链优化简化代码:
无感支付抽象类
//过车数据
class PveInfo
{
public:
int parkId;//车场ID
int parkingType;//停车类型 固定、授权、新能源
int vehicleType;//车辆类型 大型车 小型车 自定义类型车等
int outOfDate;
int plateColor;
string plateNoStr;
int inType;//入场类型
string inTimeStr;
string outTimeStr;
int payRuleId;
string uuidStr;
int fee;
/*
...
*/
};
//无感支付抽象类
class NoTouchPayManager
{
public:
NoTouchPayManager() :m_nextChain(nullptr) {}
virtual ~NoTouchPayManager() {}
void setNextChain(shared_ptr<NoTouchPayManager> next)
{
m_nextChain = next;
}
//请求处理
virtual int payRequest( PveInfo& pve) = 0;
protected:
int sendRequestToNextHandler( PveInfo& pve)
{
if (m_nextChain != nullptr)
{
m_nextChain->payRequest(pve);
return 0;
}
else
{
return -2;
}
}
private:
shared_ptr<NoTouchPayManager> m_nextChain;
};
具体支付类(职责链节点)
//具体的无感支付类
class EtcPayManager :public NoTouchPayManager
{
public:
int payRequest(PveInfo& pve) override
{
//做无感支付与其他支付方式的互斥操作等
/*...*/
if (/*EtcPayRequest(pve) == */0)
{
return 0;//ETC支付成功
}
else
{
//ETC支付失败走下一个节点的无感支付
return sendRequestToNextHandler(pve);
}
}
};
class SmartClouldPayManager :public NoTouchPayManager
{
public:
int payRequest( PveInfo& pve) override
{
if (SmartClouldPayRequest(pve) == 0)
{
return 0;//智慧云支付成功
}
else
{
//智慧云支付失败走下一个节点无感支付
return sendRequestToNextHandler(pve);
}
}
};
class ThirdPlatformPayManager :public NoTouchPayManager
{
public:
int payRequest( PveInfo& pve) override
{
if (ThirdPlatformPayRequest(pve) == 0)
{
return 0;//第三方平台支付成功
}
else
{
//第三方平台支付失败走下一个节点无感支付
return sendRequestToNextHandler(pve);
}
}
};
支付单元调用
//计费单元 无感计费函数
int PayFeeUtil::NoTouchPay(PveInfo& pve)
{
//职责链实际在软件启动时根据配置文件的优先级顺序构建 全局单利获取使用
auto PayObjEtc = make_shared<EtcPayManager>(new EtcPayManager());
auto SmartClouldObj = make_shared<SmartClouldPayManager>(new SmartClouldPayManager());
auto ThirdPlatformObj = make_shared<ThirdPlatformPayManager>(new ThirdPlatformPayManager());
PayObjEtc->setNextChain(SmartClouldObj);
SmartClouldObj->setNextChain(ThirdPlatformObj);
//开启当前车辆uuid无感支付flag防止其他(扫码、现金、刷卡等)支付导致重复扣费
if (0 == PayObjEtc->payRequest(pve))
{
//支付成功 开闸 刷新过车状态 刷新主界面状态 放行记录等
return 0;
}
//支付失败
//关闭当前车辆uuid无感支付flag 开放其他(扫码、现金、刷卡等)支付方式
return -1;
}
通过职责链模式解决了几种无感支付之间的竞态问题和优先级可控问题;项目中除却无感支付外,许多部分也可以用功能链优化,可以使得程序封装性和拓展性更好;如过车数据的处理,从相机抓拍回调->解析车牌车身等信息->解析保存车牌等图片->添加流水号保存数据->...直到处理完过车数进入过车线程中,类似流水线的处理流程均可以功能链优化,但同时也会增加程序的调试难度。

559

被折叠的 条评论
为什么被折叠?



