策略模式,又叫政策模式
定义:定义一组算法,将每个算法都封装起来,并使它们之间可以互换。
这里说到的算法就是函数;
封装起来就是用基类声明虚函数,用子类继承并实现功能;
可以互换表示必须用基类作为与外部调用模块的耦合,而不使功能类与外部产生耦合;
这种模式充分利用了对接口基类的继承,也导致了类数量的增多和复用性的减弱。
当调用模块需要用到某种策略时,只需要临时生成一个该策略对象调用即可,一个执行模块对应多个策略。
类图摘自设计模式之禅,如下:
优点:
通过对基类策略action()的封装,子类的扩展,保证了对外提供“可*切换”的策略。
要啥用啥,避免使用大量判断。
扩展性好,只要实现接口就可,如一个可反复拆卸的插件。
缺点:
每个策略都是一个类,导致类的数量多,复用性差。
所有策略类都对外暴露,因为上层模块需要知道策略的作用然后在考虑使用,违背了迪米特法则,但可以通过其他设计模式修正该缺陷。
使用场景:
多个类只在算法上有差异,如筛选过程(筛选标准可作为算法策略)
算法需要*切换的场景,算法的选择由使用者决定,或算法本身在不断进化,如灯光颜色类型(rgb,CMYK等可作为策略)等。
需要屏蔽算法规则的场景,如传个数字给个结果,不想知道过程和原因时。
注意事项:
如果策略家族数量超过4个,就需要考虑混合模式,解决策略类膨胀和对外暴露的问题,否则维护难度很大。
代码示例:张三面对不同对象时的不同应对策略
class Strategy
{
public:
virtual void action() = 0;
};
class Context
{
public:
void SetStrategy(Strategy* strategy)
{
mStrategy = strategy;
}
void strategy()
{
mStrategy->action();
}
protected:
Strategy* mStrategy;
};
class MeetSon:public Strategy
{
public:
virtual void action()
{
SaySomethingToSon();
DoSomethingForSon();
ByeToSon();
}
private:
void SaySomethingToSon()
{
cout << "你好啊儿子" << endl;
}
void DoSomethingForSon()
{
cout << "来零花钱拿着" << endl;
}
void ByeToSon()
{
cout << "快回家,注意安全啊" << endl;
}
};
class MeetWife :public Strategy
{
public:
virtual void action()
{
SaySomethingToWife();
DoSomethingForWife();
DoSomethingExtraWithWife();
ByeToWife();
}
private:
void SaySomethingToWife()
{
cout << "老婆好,今天好漂亮" << endl;
}
void DoSomethingForWife()
{
cout << "这是我这个月的工资,你帮我保管下可以不" << endl;
}
void DoSomethingExtraWithWife()
{
cout << "和老婆一起做会运动" << endl;
}
void ByeToWife()
{
cout << "老婆再见" << endl;
}
};
class MeetBoss :public Strategy
{
public:
virtual void action()
{
SaySomethingToBoss();
DoSomethingForBoss();
}
private:
void SaySomethingToBoss()
{
cout << "老板好" << endl;
}
void DoSomethingForBoss()
{
cout << "自愿加班干活" << endl;
}
};
void func()
{
Context* ZhangSan = new Context();
Strategy* Son = new MeetSon();
Strategy* Wife = new MeetWife();
Strategy* Boss = new MeetBoss();
cout << "张三见到了儿子" << endl;
ZhangSan->SetStrategy(Son);
ZhangSan->strategy();
cout << endl;
cout << "张三见到了老婆" << endl;
ZhangSan->SetStrategy(Wife);
ZhangSan->strategy();
cout << endl;
cout << "张三见到了老板" << endl;
ZhangSan->SetStrategy(Boss);
ZhangSan->strategy();
cout << endl;
}
int main()
{
func();
return 0;
}
通过策略模式达到了多态,如果还有其他策略,也可以通过继承Strategy继续扩展,扩展性良好。
同时每个策略的详细实现都不一样,类中具体的扩展全部设置为private,达到高内聚的要求。
只通过action()与调用模块耦合,达到了低耦合的要求。
调用模块不需要知道策略干了什么,只需要调用策略就可以,很方便。