策略模式
strategy model
在项目开发过程中,经常有许多if-else if等结构。比如所这样一段代码
enum class Carrier {
OPENCV = 0,
LIBYUV,
FFMPEG
};
if (handler == Carrier::OPENCV) {
return OpenCVProcess();
} else if (handler == Carrier::LIBYUV) {
// ....
} else if (hander == Carrier::FFMPEG) {
}
//或者写成switch的模式
switch(handler) {
case OPENCV:
// do something
break;
// .....
}
上述写法,就是根据不同的策略来选择相应的处理的方式,所以有很多的if else
那么这段代码可能存在什么问题呢?我至少可以说出两个不好之处。
- 如果后面出现新的处理方式是不是需要再添加一个else if ,有可能不只是这里一处需要修改,可能需要修改许多地方。
而且这里违背了“开闭原则”,我们做拓展的时候,不应该去修改源码,如果我们修改了源码,所有的与之相关的东西都需要重新编译,代码的复用性就很差。
2.如果我在当前环境中没有ffmpeg,我也不需要使用ffmpeg,那么上面的代码是编译不通过的。这是一个什么问题呢,就是抽象不应该依赖于具体的实现。
那么这段代码可以怎么改呢,这里就需要用到strategy模式。
class BaseHandler {
public:
virtual return_type Process();
virtual ~BaseHandler();
};
class ImageHandler {
private:
static BaseHandler* handler = nullptr;
ImageHandler() = delete;
public:
static bool CreateNewImageHandler(HandlerFactory* handlerFactory) {
if (!handler) {
this->hander = handlerFactory->CreateNewHandler(); // 这里使用工厂模式创建handler
}
}
return_type DoProcess() {
if (handler) {
this->handler->Process();
}
}
~ImageHandler() {
if (handler) {
delete this->handler;
this->handler = nullptr;
}
}
};
class OpenCVHandler : public BaseHander{
public:
return_type Process() {
// .....
}
~ OpenCVHandler();
};
这样就可以通过策略模式和工厂模式创建一个handler, 而且只需要包含自己想用的Carrier就行了,而不必要添加更多的if-else.
而且这种方式拓展更加灵活,编译更加快捷,符合开闭原则。
其实这也是一种将“早绑定”变为“晚绑定”的过程。
最后看看定义
策略模式定义一系列算法,将它们(变化的部分)一个个封装起来,让它们可以相互的替换。该模式使得算法可独立于稳定的客户程序。
1.strategy模式及其子类为组件提供了一系列的可重用的算法,从而使得类型在运行时可以根据需要在各个算法之间转换。
2.strategy模式 提供给程序员除 if-else , switch以外的另外的选择。消除if-else这种结构其实就是“解耦合”的过程。
3.strategy模式对象没有实例变量,那么各个上下文就可以共享同一个strategy对象,从而减少对象实例开销。
这第3条需要理解下,就是strategy模式下, strategy本身是没有对象实例的,它保存着一个抽象的handler的基类指针,而这个抽象的基类指针又是通过单例模式创建的,
所以全局只保留一个实例变量,减少系统实例的开销。
具体的handler需要继承基类handler并且,override里面的process方法。而具体处理又是运用到多态的性质,实现运行时绑定。