本文共 3710 字,大约阅读时间需要 12 分钟。
策略模式
在GOF的《设计模式:可复用面向对象软件的基础》一书中对策略模式是这样说的:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。该模式使得算法可独立于使用它的客户而变化。
策略模式为了适应不同的需求,只把变化点封装了,这个变化点就是实现不同需求的算法,但是,用户需要知道各种算法的具体情况。就像上面的加班工资,不同的加班情况,有不同的算法。我们不能在程序中将计算工资的算法进行硬编码,而是能自由的变化的。这就是策略模式。
UML类图
Strategy:定义所有支持的算法的公共接口。Context使用这个接口来调用某ConcreteStrategy定义的算法;
ConcreteStrategy:实现Strategy接口的具体算法; Context:使用一个ConcreteStrategy对象来配置;维护一个对Stategy对象的引用,同时,可以定义一个接口来让Stategy访问它的数据。
使用场合
当存在以下情况时使用Strategy模式:
代码实现
首先实现最单纯的策略模式,代码如下:
#includeusing namespace std; // The abstract strategyclass Strategy{public: virtual void AlgorithmInterface() = 0;}; class ConcreteStrategyA : public Strategy{public: void AlgorithmInterface() { cout<<"I am from ConcreteStrategyA."< AlgorithmInterface(); }private: Strategy *pStrategy;}; int main(){ // Create the Strategy Strategy *pStrategyA = new ConcreteStrategyA; Strategy *pStrategyB = new ConcreteStrategyB; Strategy *pStrategyC = new ConcreteStrategyC; Context *pContextA = new Context(pStrategyA); Context *pContextB = new Context(pStrategyB); Context *pContextC = new Context(pStrategyC); pContextA->ContextInterface(); pContextB->ContextInterface(); pContextC->ContextInterface(); if (pStrategyA) delete pStrategyA; if (pStrategyB) delete pStrategyB; if (pStrategyC) delete pStrategyC; if (pContextA) delete pContextA; if (pContextB) delete pContextB; if (pContextC) delete pContextC;}
在实际操作的过程中,我们会发现,在main函数中,也就是在客户端使用策略模式时,会创建非常多的Strategy,而这样就莫名的增加了客户端的压力,让客户端的复杂度陡然增加了。那么,我们就可以借鉴简单工厂模式,使策略模式和相结合,从而减轻客户端的压力,代码实现如下:
#includeusing namespace std; // Define the strategy typetypedef enum StrategyType{ StrategyA, StrategyB, StrategyC}STRATEGYTYPE; // The abstract strategyclass Strategy{public: virtual void AlgorithmInterface() = 0; virtual ~Strategy() = 0; // 谢谢hellowei提出的bug,具体可以参见评论}; Strategy::~Strategy(){} class ConcreteStrategyA : public Strategy{public: void AlgorithmInterface() { cout << "I am from ConcreteStrategyA." << endl; } ~ConcreteStrategyA(){}}; class ConcreteStrategyB : public Strategy{public: void AlgorithmInterface() { cout << "I am from ConcreteStrategyB." << endl; } ~ConcreteStrategyB(){}}; class ConcreteStrategyC : public Strategy{public: void AlgorithmInterface() { cout << "I am from ConcreteStrategyC." << endl; } ~ConcreteStrategyC(){}}; class Context{public: Context(STRATEGYTYPE strategyType) { switch (strategyType) { case StrategyA: pStrategy = new ConcreteStrategyA; break; case StrategyB: pStrategy = new ConcreteStrategyB; break; case StrategyC: pStrategy = new ConcreteStrategyC; break; default: break; } } ~Context() { if (pStrategy) delete pStrategy; } void ContextInterface() { if (pStrategy) pStrategy->AlgorithmInterface(); } private: Strategy *pStrategy;}; int main(){ Context *pContext = new Context(StrategyA); pContext->ContextInterface(); if (pContext) delete pContext;}
在上面这个代码中,其实,我们可能看到的更多的是简单工厂模式的应用,我们将策略模式将简单工厂模式结合在了一起,让客户端使用起来更轻松。
总结
策略模式和状态模式,是大同小异的;状态模式讲究的是状态的变化,和不同状态下,执行的不同行为;而策略模式侧重于同一个动作,实现该行为的算法的不同,不同的策略封装了不同的算法。策略模式适用于实现某一功能,而实现该功能的算法是经常改变的情况。在实际工作中,遇到了实际的场景,可能会有更深的体会。比如,我们做某一个系统,该系统可以适用于各种数据库,我们都知道,连接某一种数据库的方式是不一样的,也可以说,连接数据库的“算法”都是不一样的。这样,我们就可以使用策略模式来实现不同的连接数据库的策略,从而实现数据库的动态变换。