目录
策略模式基本概念
策略模式的应用场景
实际项目中具体应用
项目背景:
策略模式解决方案:
计费模块策略模式简要代码
策略模式基本概念
策略模式(Strategy Pattern) 是一种行为型设计模式,把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离,即算法本身和使用算法的客户端代码是解耦的。简单来说,策略模式就是定义了一系列的算法,并将每一个算法封装起来,使它们可以相互替换。策略模式使得算法可独立于使用它的客户而变化。
策略模式的应用场景
策略模式在软件开发中有着广泛的应用场景,包括但不限于以下几种情况:
(1)多种算法的实现:当存在多种算法,而这些算法的实现又需要频繁地更换或扩展时,可以考虑使用策略模式。通过定义不同的策略类来实现不同的算法,客户端可以根据需要选择具体的策略。
(2)条件分支语句的替代:在程序中,如果存在大量的条件分支语句(如if-else或switch-case),并且这些条件分支语句的实现逻辑比较复杂或容易变化时,可以考虑使用策略模式来替代这些条件分支语句。通过定义不同的策略类来实现不同的分支逻辑,客户端可以根据条件选择具体的策略。
(3)算法与数据结构的分离:在某些情况下,我们可能需要将算法与数据结构进行分离,以便能够独立地修改或扩展它们。这时,可以使用策略模式来将算法封装成独立的策略类,从而实现算法与数据结构的分离。
(4)可配置的行为:在某些系统中,某些行为可能需要根据配置或用户的选择来改变。这时,可以使用策略模式来定义不同的策略类,并根据配置或用户的选择来选择具体的策略。
实际项目中具体应用
项目背景:
在停车场项目中车辆的计费规则是一个剧烈变动的因素,在全国不同地区不同厂库计费规则各不相同,即使同一个厂库也随着发改委的文件需要时长修改;此外随着停车场软件的逐步迭代升级,现场升级软件又难免需要迁移计费规则,从而导致大量的迁移和编译工作,占用不少的研发资源。
策略模式解决方案:
项目需要解决的问题主要是: 千变万化的收费规则接入(程序扩展性)和规则在不同版本之间迁移;
针对规则的剧烈变化在计费模块中不同的计费规则采用策略模式独立继承策略抽象类独立编码,从而保证计费模块的封装性。对于规则在不同版本之间的迁移,可以采用Qt的插件将不同的计费策略编译为插件,便于适用不同版本的程序,关于插件参考Qt插件博客,此处着重介绍策略模式的使用。
计费模块策略模式简要代码
计费抽象策略接口定义:
//计费车辆相关信息
class PveInfo
{
public:
int parkId;//车场ID
int parkingType;//停车类型 固定、授权、新能源
int vehicleType;//车辆类型 大型车 小型车 自定义类型车等
int outOfDate;
int plateColor;
string plateNoStr;
int inType;//入场类型
string inTimeStr;
string outTimeStr;
int payRuleId;
//结算,优惠,处理状态等其他信息
/*
...
*/
};
class CalcParkingFee
{
public:
CalcParkingFee() = default;
virtual ~CalcParkingFee() = default;
virtual int calcFee(const PveInfo&) = 0;
};
具体计费策略继承实现
class OneTimeCalc :public CalcParkingFee
{
public:
OneTimeCalc() = default;
~OneTimeCalc() = default;
int calcFee(const PveInfo&) override
{
//按次收费具体计费
return 0;
}
};
//停车时长阶梯计费
class StageCalc :public CalcParkingFee
{
public:
StageCalc() = default;
~StageCalc() = default;
int calcFee(const PveInfo&) override
{
return 0;
}
};
//日夜分时按次计费
class DayAndnightCalc :public CalcParkingFee
{
public:
DayAndnightCalc() = default;
~DayAndnightCalc() = default;
int calcFee(const PveInfo&) override
{
return 0;
}
};
计费引擎匹配策略类:
class CalcFeeEngine
{
private:
std::unique_ptr<CalcParkingFee> strategy;
public:
CalcFeeEngine(std::unique_ptr<CalcParkingFee> strategy)
: strategy(std::move(strategy)) {}
void setStrategy(std::unique_ptr<CalcParkingFee> newStrategy) {
strategy = std::move(newStrategy);
}
int calcFee(const PveInfo& pveInfo) const {
return strategy->calcFee(pveInfo);
}
};
计费单元计费示例
int CalcFeeUtil::calc(PveInfo& pveInfo)
{
//根据车辆类型 停车类型等匹配计费规则
if (0 == matchPayRule(pveInfo))
{
//处理pveInfo 减免 优惠券 折扣 节假日等
/*
...
*/
CalcFeeEngine calcEngine(mapId2CalcObj[pveInfo.payRuleId]);
return calcEngine.calcFee();
}
else
{
//...
}
}
通过策略模式优化车辆计费模块,使得计费规则策略独立于计费单元的,从而保证了计费单元的稳定性和计费规则的可扩展性;最终将具体的计费规则单独以插件的形式接入程序,从而保证不同项目不同版本的程序计费规则的开发和迁移独立于主程序,极大的节约了开发资源。