设计模式(二):策略模式
简单工厂模式是客户告诉工厂所需要的对象,然后由工厂生产对象交给客户,客户去具体考虑的使用对象中的方法。而策略模式则有所不同,客户自己创建对象,但是当客户需要调用对象的方法时,则交由另一个环境角色类(Context)来实现,客户本身不关心方法的具体实现过程。
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。在这种模式中,主要有三种角色:
- 抽象策略角色: 策略类,通常由一个接口或者抽象类实现。
- 具体策略角色:包装了相关的算法和行为。
- 环境角色:持有一个策略类的引用,最终给客户端调用。
简单来说,策略模式中客户产生其所想要的具体策略所对应的对象,并传给环境角色,由环境角色来完成具体策略的调用然后返回给客户。
还是以计算器为例,当客户需要加法运算时,就生产一个加法运算的对象,并输入加法运算的两个操作数,这时候把这个对象丢给环境角色,环境角色就会去调用具体实现加法的算法并将结果返回给客户。因此策略模式的优点是隔离了客户和具体方法,适合类中的成员以方法为主、算法经常变动的情况。但是策略模式也有明显的缺点,那就是在客户端去判断应该使用哪一个对象并要生产它,那么现在我们考虑将策略模式与简单工厂模式相结合,看看会有什么效果。我们给工厂角色加入环境角色的功能,也就是说对象的生产仍然通过客户告诉工厂角色来完成,同时工厂角色调用所产生对象的具体方法并将结果返回给客户。这么做的好处是客户无需关心对象的生产和具体方法的实现,在客户端只需知道工厂角色一个类就可以,综合了两种模式的优点。
综合回顾一下三种模式,试想有一个机器,它承担着工厂角色、环境角色或是两者结合的职责。在简单工厂模式中,客户在机器上输入对象的名称,机器就把这个对象生产出来,客户拿到这个对象就能使用它的方法;在策略模式中,客户把自己手里的对象放到这个机器里,机器去调用对象的方法,把结果显示给客户;而在两种模式相结合的情况下,客户在机器上输入对象的名称,机器把这个对象生产出来并调用它的方法,最后把结果显示给客户。
下面给出策略模式代码,由于运算基类、具体运算类和简单工厂模式一样就不再重复了,只给出环境角色类和客户端部分。
class Context//环境角色类 { private: COperation* op;//指向客户产生的对象 public: Context(COperation* temp, int firstNum, int secondNum) { op=temp; op->SetFirst(firstNum); op->SetSecond(secondNum); } double GetResult()//调用对象的具体方法 { return op->GetResult(); } ~Context() { delete op; } }; int main() { int firstNum, secondNum; char oper; cout << "Please input first number:" << endl; cin >> firstNum; cout << "Please input operator:" << endl; cin >> oper; cout << "Please input second number:" << endl; cin >> secondNum; Context *context; switch(oper) { case '+': context=new Context(new CAdd(), firstNum, secondNum); break; case '-': context=new Context(new CSub(), firstNum, secondNum); break; } cout << "The result is: " << context->GetResult() << endl; return 0; }
下面是两种模式相结合的代码:
class FactoryContext//简单工厂与策略模式混合类 { private: COperation* op; public: FactoryContext(char cType, int firstNum, int secondNum) { switch (cType)//根据客户要求生产对象 { case '+': op=new CAdd(); op->SetFirst(firstNum); op->SetSecond(secondNum); break; case '-': op=new CSub(); op->SetFirst(firstNum); op->SetSecond(secondNum); break; } } double GetResult()//调用所生产对象的具体方法 { return op->GetResult(); } ~FactoryContext() { delete op; } }; int main()//客户端 { int firstNum, secondNum; char oper; cout << "Please input first number:" << endl; cin >> firstNum; cout << "Please input operator:" << endl; cin >> oper; cout << "Please input second number:" << endl; cin >> secondNum; FactoryContext *conFactory = new FactoryContext(oper, firstNum, secondNum); cout << "The result is: " << conFactory->GetResult() << endl; delete conFactory; return 0; }