策略模式意图将解决问题的算法分别封装成一个个对象的形式,并使这些算法对象相互间可被替换。模式比较简单,对于策略对象结构的设计,可抽象一个抽象基类,并定义好相关算法(纯)虚接口,并由各种具体的实现算法子类实现即可。因此模式的类关系结构图参考如下:
模式编码结构参考如下:
1 namespace strategy 2 { 3 class IAbstractStrategy 4 { 5 public: 6 // some code here........ 7 virtual void executeAlgorithm() = 0; 8 9 };//class IAbstractStrategy 10 11 class ConcreteStrategy1 : public IAbstractStrategy 12 { 13 public: 14 // some code here........ 15 virtual void executeAlgorithm() override { 16 // some code here........ 17 // execute real algorithm code. 18 // some code here........ 19 } 20 21 };//class ConcreteStrategy1 22 23 class ConcreteStrategy2 : public IAbstractStrategy 24 { 25 public: 26 // some code here........ 27 virtual void executeAlgorithm() override { 28 // some code here........ 29 // execute real algorithm code. 30 // some code here........ 31 } 32 33 };//class ConcreteStrategy2 34 35 class Context 36 { 37 public: 38 // some code here........ 39 void doSomething(IAbstractStrategy* pStrategy) { 40 // e.g 41 if (nullptr != pStrategy) { 42 pStrategy->executeAlgorithm(); 43 } 44 } 45 46 }; 47 48 }//namespace strategy
策略模式主要是在当一个问题的解存在不止一种方案并且这些解有可能随时被替换相互替换的情况下使用。如游戏中的角色的目标选择方案就可考虑使用策略模式。如游戏中的角色技能也可考虑使用策略模式,同一角色当前正在使用普通技能,过会就可能使用法术技能等等。在这些情况下使用策略模式是挺方便的,比较后期想有了新的具体实现策略时,不需要对应用的逻辑结构进行调整,只需要新扩展一个具体实现策略即可。
在编码实现上,设计人员可能需要考虑数据信息如何传递给对应的策略对象中,此时可能需要视具体的环境而定。一种可参考的方案可将策略所需的数据信息骑过参数形式传入。这种方案对于不同的具体实现策略对象来说,却并不一定全都有用。甚至有时为了某个特别的具体实现策略对象来说,需要的参数很多,于是在抽象类上就将所有参数都列入。可实际上,这些参数中的绝对大多数却有可能对其他的那些具体实现策略来说,是完全没有用的。并且后期如果扩展新的实现策略的话,则有可能会影响整个策略类系的接口重新调整。第二种可参考的方案是直接将上下文对象作为参数传入。该方案对于策略类系来说,结构比较稳定,并且任何一个新的或旧的具体实现策略都可以取到它们自己所需要的数据信息。但是这种情况下,势必要求上下文对象必需开放过多的(甚至是)不必要的接口出来。这样就无形当中破坏了封装性。