定义:定义一组算法,将每个算法都封装起来,并使它们之间可以互换。
这里说到的算法就是函数;
封装起来就是用基类声明虚函数,用子类继承并实现功能;
可以互换表示必须用基类作为与外部调用模块的耦合,而不使功能类与外部产生耦合;
这种模式充分利用了对接口基类的继承,也导致了类数量的增多和复用性的减弱。
当调用模块需要用到某种策略时,只需要临时生成一个该策略对象调用即可,一个执行模块对应多个策略。
类图摘自设计模式之禅,如下:
优点:
通过对基类策略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()与调用模块耦合,达到了低耦合的要求。
调用模块不需要知道策略干了什么,只需要调用策略就可以,很方便。