策略模式

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
那么这段代码可能存在什么问题呢?我至少可以说出两个不好之处。

  1. 如果后面出现新的处理方式是不是需要再添加一个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方法。而具体处理又是运用到多态的性质,实现运行时绑定。

posted @ 2020-11-09 11:01  cyssmile  阅读(107)  评论(0编辑  收藏  举报