注意,模板方法模式是“坚持相同的代码”,而被覆盖的函数是“变化的代码”。然而,这种变化在编译时通过继承被固定下来。按照“组合优于继承”的格方,可以利用组合来解决将变化的代码从“坚持相同的代码”中分开的问题,从而产生策略(Strategy)模式。这种方法有一个明显的好处:在程序运行时,可以插入变化的代码。策略模式也加入了“语境”,它可以是一个代理类,这个类控制着对特定策略对象的选择和使用--就像状态模式一样。
“策略”的意思就是:可以使用多种方法来解决某个问题--即“条条大路通罗马”。现在考虑一下忘记了某个人姓名时的情景。这里的程序可以用不同方法解决这个问题。
//: C10:Strategy.cpp // The Strategy design pattern. #include <iostream> using namespace std; class NameStrategy { public: virtual void greet() = 0; }; class SayHi : public NameStrategy { public: void greet() { cout << "Hi! How's it going?" << endl; } }; class Ignore : public NameStrategy { public: void greet() { cout << "(Pretend I don't see you)" << endl; } }; class Admission : public NameStrategy { public: void greet() { cout << "I'm sorry. I forgot your name." << endl; } }; // The "Context" controls the strategy: class Context { NameStrategy& strategy; public: Context(NameStrategy& strat) : strategy(strat) {} void greet() { strategy.greet(); } }; int main() { SayHi sayhi; Ignore ignore; Admission admission; Context c1(sayhi), c2(ignore), c3(admission); c1.greet(); c2.greet(); c3.greet(); } ///:~ .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }Context::greet()可以正规地写得更复杂些,它类似模板方法模式,因为其中包含了不能改变的代码。但在函数main()中可以看到,可以在运行时就策略进行选择。更进一步的做法,可以将状态模式与在Context对象的生存期期间的变化的策略模式结合起来使用。
Chain of Responsibility:尝试采用一系列策略模式。
职责链模式也许被看做一个使用策略对象的“递归的动态一般化”。此时提出一个调用,在一个链序列中的每个策略都试图满足这个调用。这个过程直到有一个策略成功满足该调用或者到达链序列的末尾才结束。在递归方法中,有个函数反复调用其自身直至达到某个终止条件。
//: C10:ChainOfReponsibility.cpp // The approach of the five-year-old. #include <iostream> #include <vector> #include "../purge.h" using namespace std; enum Answer { NO, YES }; class GimmeStrategy { public: virtual Answer canIHave() = 0; virtual ~GimmeStrategy() {} }; class AskMom : public GimmeStrategy { public: Answer canIHave() { cout << "Mooom? Can I have this?" << endl; return NO; } }; class AskDad : public GimmeStrategy { public: Answer canIHave() { cout << "Dad, I really need this!" << endl; return NO; } }; class AskGrandpa : public GimmeStrategy { public: Answer canIHave() { cout << "Grandpa, is it my birthday yet?" << endl; return NO; } }; class AskGrandma : public GimmeStrategy { public: Answer canIHave() { cout << "Grandma, I really love you!" << endl; return YES; } }; class Gimme : public GimmeStrategy { vector<GimmeStrategy*> chain; public: Gimme() { chain.push_back(new AskMom()); chain.push_back(new AskDad()); chain.push_back(new AskGrandpa()); chain.push_back(new AskGrandma()); } Answer canIHave() { vector<GimmeStrategy*>::iterator it = chain.begin(); while(it != chain.end()) if((*it++)->canIHave() == YES) return YES; // Reached end without success... cout << "Whiiiiinnne!" << endl; return NO; } ~Gimme() { purge(chain); } }; int main() { Gimme chain; chain.canIHave(); } ///:~ 职责链的本质是尝试多个解决方法直到找到一个起作用的方法。