关于停更了一个月的说明
本人于8月底入职了新公司,由于刚入职,业务和新公司技术架构熟悉都花费了大量时间,而且又赶上入职就被安排了一个十一前必须上线的需求,因此本专栏鸽了1个月。。。先向之前关注了我的设计模式专栏而白白等待的学友说一声对不起。从本周起开始保持每周更新。
前言
由于设计模式章节将贴出大量伪代码,为了压缩代码长度方便大家查看,因此代码段中与设计模式无关的代码,如构造函数、或是成员函数public、private、protect属性等均未写出。文章中若有说明不清晰或是有歧义、错误的地方欢迎大家评论指正,谢谢大家。
一、定义
策略模式的定义是:策略模式作为一种软件设计模式,指对象有某个行为,但是在不同的场景中,该行为有不同的实现算法。比如每个人都要“交个人所得税”,但是“在美国交个人所得税”和“在中国交个人所得税”就有不同的算税方法。这是百度百科的官方解释。换个白话来说,在对相似的行为进行判断执行时不再使用if else if else或是switch case来做处理,而是将每个算法封装起来,让它们可以相互替换。换句话说,策略模式通常把一系列算法,封装到一系列具体策略类中来作为抽象策略类的子类。
二、要素
策略类的基本三要素是:
1、抽象策略角色: 策略类,通常由一个接口或者抽象类实现。
2、具体策略角色:包装了相关的算法和行为。
3、环境角色:持有一个策略类的引用,最终给客户端调用。
三、事例场景
我们就以百度百科中策略模式定义里面的例子来当做本文章的案例。现在有业务场景需要给下游提供缴纳个人所得税的接口。已知美国税率为15%,中国税率为3%。请设计一个接口。
四、一般实现
一般实现代码如下,看起来也没什么可优化的地方。但实际上一般使用if或是Switch实现的代码存在2个问题:
1、如果新增一个国家的纳税算法,我们需要改动getTaxes接口,这不符合设计模式中的开闭原则。
2、如果当纳税算法非常多时,比如有50个国家的50种不同纳税算法。那这种设计显然是不合理的,非常不易于阅读和维护。
class people
{
typedef enum country
{
CN = 0,
USA = 1
};
double getTaxes(double salary, country c);
{
double ret = 0;
if(c == CN)
{
ret = salary - (salary * 0.03);
}
else
{
ret = salary - (salary * 0.15);
}
return ret;
}
};
五、采用策略模式
上面提到了策略模式的三要素,因此策略模式将不止包含一个people类,还存在另外两个类,代码实现如下:
/*
1、抽象策略角色: 策略类,通常由一个接口或者抽象类实现。
2、具体策略角色:包装了相关的算法和行为。
3、环境角色:持有一个策略类的引用,最终给客户端调用。
*/
//担任环境角色
class people
{
double getTaxes(double salary, baseTaxes* country);
{
return country->getTaxes(salary);
};
};
//担任抽象策略角色
class baseTaxes
{
virtual double getTaxes(double salary) = 0;
virtual ~baseTaxes(){};
};
//担任具体策略角色-中国纳税算法
class CNTaxes
{
double getTaxes(double salary)
{
return salary - (salary * 0.03);
};
};sorry
//担任具体策略角色-美国纳税算法
class USATaxes
{
double getTaxes(double salary)
{
return salary - (salary * 0.15);
};
};
其实策略模式实现的纳税算法处理,代码并不复杂,使用类的继承关系替代了if判断。在该模式下,当我们需要增加一个新的国家纳税算法时,只需要继承baseTaxes类实现一个新的国家纳税类并实现getTaxes接口,即可在不改动其它代码的情况下新增一个纳税算法。符合了设计模式的开闭原则。同时大大增加了代码的可读性,杜绝了超长函数的出现。
六、策略模式的缺点
使用策略模式也有缺点,当我们的算法很多时,将会从抽象策略角色派生出大量的具体策略类,同时调用者在使用时也必须知道每个算法对应的类按照下列格式使用,会增加使用者的调用难度.
int main(int argc, char** argv)
{
people* person = new people();
baseTaxes* country = new CNTaxes();
printf("税前工资为8000, 在中国的税后工资为%lf\n", person->getTaxes(8000, country));
delete person;
delete country;
return 0;
}