strategy模式
这次遇到它不是在项目中,但项目也有的。。今天实际上发现,在项目中23种设计模式的基本用法都作了示例。。原型也都规定好了。。
策略模式是在读ThoughtWork文集里看到的,还提及了Null Object模式,两个都大致说下。
The strategy pattern is intended to provide a means to define a family of algorithms, encapsulate each one as an object, and make them interchangeable. The strategy pattern lets the algorithms vary independently from clients that use them. 这样我们可以运行里,切换算法的实现。
上图(from wiki):
实际上,在一些情况下,我们已经不自觉的在使用这一模式了,不知道你是不是也有同感。
再来一段示例代码:
#include <iostream> using namespace std; class StrategyInterface { public: virtual void execute() const = 0; }; class ConcreteStrategyA: public StrategyInterface { public: virtual void execute() const { cout << "Called ConcreteStrategyA execute method" << endl; } }; class ConcreteStrategyB: public StrategyInterface { public: virtual void execute() const { cout << "Called ConcreteStrategyB execute method" << endl; } }; class ConcreteStrategyC: public StrategyInterface { public: virtual void execute() const { cout << "Called ConcreteStrategyC execute method" << endl; } }; class Context { private: StrategyInterface * strategy_; public: explicit Context(StrategyInterface *strategy):strategy_(strategy) { } void set_strategy(StrategyInterface *strategy) { strategy_ = strategy; } void execute() const { strategy_->execute(); } }; int main(int argc, char *argv[]) { ConcreteStrategyA concreteStrategyA; ConcreteStrategyB concreteStrategyB; ConcreteStrategyC concreteStrategyC; Context contextA(&concreteStrategyA); Context contextB(&concreteStrategyB); Context contextC(&concreteStrategyC); contextA.execute(); // output: "Called ConcreteStrategyA execute method" contextB.execute(); // output: "Called ConcreteStrategyB execute method" contextC.execute(); // output: "Called ConcreteStrategyC execute method" contextA.set_strategy(&concreteStrategyB); contextA.execute(); // output: "Called ConcreteStrategyB execute method" contextA.set_strategy(&concreteStrategyC); contextA.execute(); // output: "Called ConcreteStrategyC execute method" return 0; }
好,下面说Null Object模式,很容易,先上代码:
class animal { public: virtual void make_sound() = 0; }; class dog : public animal { void make_sound() { cout << "woof!" << endl; } }; class null_animal : public animal { void make_sound() { } };
你一定不知道这段代码有什么神奇的地方,那就听我慢慢说。
在一些场合下,假设我们需要传一个引用参数,这没什么,但要说明这个引用可能为“空”。好,怎么表示这个空?Java中没有问题,null就搞定了;那C++这种东西呢? 当然我们可以说用指针来绕过这一问题,但你对这个答案满意么?
好,我们看看这段代码,把null_animal这个东西认为是一个类似NULL的东西如何呢?
这种做法不但可以解决问题,还会有一些其它的好处。
比如,当然类型是一个数组(比如java中的list)时,我们可能要对返回值为null的情形特殊处理,但如果返回这样一个无害的对象,其iterator可以正常调用但不会产生什么实际效果,这样是不是更好呢?
这样的用法,至少可以减少分支(if else)数,使方法的代码行数减少,结构明析。
再一点好处,我们可以把这种对象作为桩来用--万一我们的测试还差一部分才能做,而这一部分一时半会儿完不成但我们暂时用不太到时。