昨天累的要死,晚上还头痛好长时间,今早起来,八点多到自习室,完成昨天没完事的设计模式“策略模式”的研究。
1.初识策略模式
首先还是看看定义吧:策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换,策略模式让算法独立于使用它的客户而独立变化。
策略模式包括以下几个部分的内容:
(1)—抽象策略角色: 策略类,通常由一个接口或者抽象类实现。
(2)—具体策略角色:包装了相关的算法和行为。
(3)—环境角色:持有一个策略类的引用,最终给客户端调用。
学习设计模式也要注重类图,这往往很直观:
2.举例了解策略模式
前面从理论上初步了解一下什么是策略模式,想必是不太好理解,现在通过一个例子说明到底什么是设计模式。大家都知道美国和我们中国的交个人所得税的方式是不一样的。这是一个本人认为比较典型的一个策略模式应用的例子,采用策略模式的设计如下:
//strategy类 class StrategyInterface { public: virtual void execute() = 0; }; //中国的收税策略 class ConcreteStrategyChina: public StrategyInterface { public: virtual void execute() { cout << "Called ConcreteStrategyChina execute method" << endl; } }; //美国的收税策略 class ConcreteStrategyAmerica: public StrategyInterface { public: virtual void execute() { cout << "Called ConcreteStrategyAmerica execute method" << endl; } }; //策略环境类 class Context { private: StrategyInterface *_strategy; public: Context(StrategyInterface *strategy):_strategy(strategy) { } void set_strategy(StrategyInterface *strategy) { _strategy = strategy; } void execute() { _strategy->execute(); } };
这时在客户端的使用时是比较方便的,只需要这样:
ConcreteStrategyChina concreteStrategyChina; ConcreteStrategyAmerica concreteStrategyAmerica; Context contextA(&concreteStrategyChina); ContextA.execute(); ContextA.set_strategy(&concreteStrategyAmerica); ContextA.execute();
那么,使用策略模式有什么好处呢?好处就在于:
(1) 策略模式提供了管理相关的算法族的办法,策略类的等级结构定义了一个算法或行为族,恰当使用继承可以把公共的代码移到父类里面,从而避免重复的代码。
(2) 策略模式使得算法的使用者就和算法本身分离开来,使得系统易于扩展,当要加入日本的个人所得税收费方式时,只需要在加一个Strategy的子类,并重写execute方法。
(3)从某种角度上讲,能减少测试的工作量,每个算法可以很容易进行单独测试,并且修改一个算法,也不会对其他算法类造成影响。
3.策略模式和简单工厂模式联手
但是,基础的策略模式并不是最佳的方法,其实只要和简单工厂模式结合相使用,就能使得客户端“认识”的类减少(只需要认识Context类),进一步减少耦合性,并且也使得客户端中所要做出的逻辑判断(到底用哪个具体策略)转移到工厂类中。这里我们把Context作为工厂类就可以了。看看代码吧:
class Context { private: StrategyInterface *_strategy; public: Context(string type) { switch(type) { case "美国税收": _strategy = new ConcreteStrategyAmerica();break; case "中国税收": _strategy = new ConcreteStrategyChina();break;
default: } } void execute() { _strategy->execute(); } };
这样在客户端只需要实例化Context类,并传入一个string类型的参数就能达到动态使用各种类的目的,并且客户端只需要认识Context类,这真的是太棒了。实际上在基本的策略模式中,选择所要具体使用的算法的职责还是由客户端承担,这本身没有接触客户端需要选择判断的压力,如果和简单工厂模式结合使用后,选择具体使用的算法的责任就交给了Context类,这就大大的减轻了客户端的责任。
4.什么情况下使用策略模式
(1)如果在一个系统里面有许多类,它们之间的区别仅在于它们的行为,那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。
(2) 一个系统需要动态地在几种算法中选择一种。那么这些算法可以包装到一个个的具体算法类里面,而这些具体算法类都是一个抽象算法类的子类。换言之,这些具体算法类均有统一的接口,由于多态性原则,客户端可以选择使用任何一个具体算法类,并只持有一个数据类型是抽象算法类的对象。
(3)一个系统的算法使用的数据不可以让客户端知道。策略模式可以避免让客户端接触到的复杂的只与算法有关的数据。
(4) 如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。此时,使用策略模式,把这些行为转移到相应的具体策略类里面,就可以避免使用难以维护的多重条件选择语句,并体现面向对象设计的概念。、
下面不妨举几个在实际应用中已经使用策略模式的例子:
例1:
想必经常编程序的人基本上都用过这个函数吧public virtual void Sort (IComparer comparer),可以看到Sort方法接收一个IComparer类型的参数,那么这个IComparer接口是做什么用的呢?其实是用来确定排序方式的,例如是从大到小排序还是从小到大排序等。这是conpare具体取值就是动态确定的,并且是一系列算法的集合,所以非常适合策略模式,实际上使用的也是策略模式。
例2:
还比如在玩“极品飞车”这款游戏,那么游戏对车的轮胎是可以更换的,不同的轮胎在高速转弯时有不同的痕迹样式,那么针对“汽车”的配件“轮胎”就要可以变化,而且轮胎和轮胎之间是可以相互替换的,这就是典型的要应用“策略模式”的场景!
学习中的一点总结,欢迎拍砖哈^^