为什么要使用策略模式?
在实际的项目中,对于相同对象(或数据)通常有不同的计算方法来处理这个对象(或数据)。如果项目不需要更新,那自然不需要策略模式。
但是某些对象(或数据)使用的算法可能多种多样,且经常改变。如果将这些变化都写到对象中,即会造成对象变得很复杂很难更改,而且有时候,一些用不到的算法也会成为性能负担。
例子(无策略模式)
比如不同的地区,高考区分一本线和二本线是不一样的,所以不同地区的学生的分数是否上本科线线,也有不同的算法,要求你设计一个学生的类,可以算出该学生是否上了该省的本科线。
enum Province{
SiChuan,
XiZang,
BeiJing
};
class Student{
public:
int score;
Province mLocal;
public:
bool getGrade(){
if(mLocal==SiChuan){
//
}
if(mLocal==XiZang){
//
}
if(mLocal==BeiJing){
//
}
}
}
这样写咋一看没有任何问题,但是每个实际的项目的开发都是有一个时间线的。就比如上面的例子,刚开始写好是上面的样子,但如果还有其他的算法,
比如以后要加入其他省份的本科线算法,就需要修改以上代码,这样导致代码不易复用(注意:编程中的代码复用指的是编译好的代码,如.dll或者.so文件,copy代码不叫代码复用。可能有人会说,我只加一段代码,我保证前面的代码不变不就行了?但是在实际的项目中,想要保证前面的不变是非常困难的,如果这样做,很可能出现莫名其妙的错误)。
比如将来出台新政策,四川成都地区和自贡地区的本科线不一样了,那么就要修改上述代码,代码不可扩展。
比如某一地区的计算方法写错了,需要修改,修改完又要重新编译所有代码,代码不易维护
以上三种情况严重违反了开闭原则,极有可能造成莫名其妙的代码错误!
使用策略模式的目的
1.隔离变化
把后期可能出现的变化,与不会变化的流程隔离开。避免后期修改一部分代码是造成牵一发动全身的后果。
在students类中,getGrade是变化的,所以应该隔离出来,剩下的部分保持不变。
2.编程到接口
只把接口暴露出来,避免类的使用者被无关代码干扰。
getGrade应该只是一个接口,里面实现不同省份的算法,添加或者修改这些算法都应该在接口里面进行。
例子(策略模式)
(按照c++的惯例,所有基类的析构函数都应该是虚函数)
class GradeStraegy{
public:
virtual bool Calculate() = 0;
virtual ~GradeStraegy(){}
}
class SiChuanStraegy : public GradeStraegy{
public:
virtual bool Calculate() {
//
}
}
class XiZangStraegy: public GradeStraegy{
public:
virtual bool Calculate() {
//
}
}
class BeiJingStraegy : public GradeStraegy{
public:
virtual bool Calculate(){
//
}
}
class Student{
private:
GradeStraegy *Straegy;//这是一个多态指针
public:
Student(Province mProvince){
Straegy = StraegyFactory->getProvince(mProvince);//返回多态指针
}
bool getGrade(){
return Straegy ->Calculate();//多态调用
}
}
容易扩展实际上StraegyFactory是后面要讲的一个设计模式叫工厂模式,代码这样写就把Calculate的实现与Student的实现分离开了。
如果要加入其他省份的计算方法,那么只需要在添加一个类就行了,不需要修改前面的类,前面的代码编译好了就不用修改,代码容易复用。
如果出台新政策,让四川成都地区和四川自贡地区的计算方法不一样,那么只需要在写两个子类继承自SiChuan类就行了,同样不需要修改前面的代码,代码容易扩展。
如果前面的代码写错了,也只需要修改一个类就好了,不需要修改其他类,代码容易维护。
按照c++的惯例,不同的类应该写在不同的文件里面,作者为了快速展示效果,把所有类都写在同一个文件了。但是在实际的项目中,修改一个类,只需要重新编译一个文件,修改多个类,要编译多个文件,还有可能造成莫名其妙的错误(我就遇到过很多次)。这就是策略模式的优势
策略模式的要点
1.Straegy及其子类为组件提供了一系列可重复使用的算法,从而可以是类型在运行期根据需要自由的切换算法。
2. Straegy模式提供了条件判断语句的另一种选择。含有很大条件判断的可以考虑Straegy模式。
小结
(1)面向对象三大原则:1隔离变化,2.编程到接口,3.组合优于继承
(2)策略模式主要设计“一系列不同算法”的问题。