最常用设计模式-模板方法模式

    这里主要用来讨论设计模式的模板方法模式。

简介

    模板方法模式用于应对多个对象之间存在明显的模板,仅仅少量不同的情况。将其中固定的处理流程写到父类中,变化处理方法通过虚函数的方式留给子类重载
    下面将举一个例子。为了让一个移动机器人行走,它的导航系统同时需要一个全局路径规划算法和一个局部路径规划算法。目前,可选的全局路径规划算法包括:Dijkstra, A*等;可选的局部路径规划算法包括:DWA, Trajectory Rollout等。不同的组合方式有不同的优点,所以需要不同的组合。现在面临的问题是:

  • 不同组合方式仅仅规划算法部分不一样,其他部分都是一样的。如果实现不同的组合,将会出现大量的重复代码。

    这是一个典型的模板方法模式应用场景。模板方法模式通过使用虚类,实现了"模板类"与"插件类"之间的解耦合。模板类中存放公共处理流程,插件类中存放不同的路径规划算法,由此避免了重复代码。下面是UML类图,

    具体的代码实现包含多个文件,如下,

// main.cc
/* 模板方法模式的测试 */
#include "plugin.h"

int main(){
  // 创建插件模块
  BaseLocalPlanner *local_planner = new DwaPlanner();
  BaseGlobalPlanner *global_planner = new DijkstraPlanner();
  // 创建模板类
  MoveBase move_base(global_planner, local_planner);
  move_base.doWork();

  return 0;
}
// move_base.h
/* 模板方法模式的模板类 */
#ifndef TEMPLATE_METHOD_MOVEBASE_H_
#define TEMPLATE_METHOD_MOVEBASE_H_

// 分别为全局路径规划和局部路径规划创建抽象接口
class BaseLocalPlanner{
  public:
    virtual void run()=0;
};

class BaseGlobalPlanner{
  public:
    virtual void run()=0;
};
// 模板类,该类通过抽象接口完成任务
class MoveBase{
  public:
    MoveBase(BaseGlobalPlanner *global_planner, BaseLocalPlanner *local_planner);
    void doWork();

  private:
    BaseLocalPlanner *local_planner_;
    BaseGlobalPlanner *global_planner_;
};

#endif
// move_base.cc
/* 模板方法模式的模板类 */
#include "move_base.h"

MoveBase::MoveBase(BaseGlobalPlanner *global_planner
  , BaseLocalPlanner *local_planner)
{
  global_planner_ = global_planner;
  local_planner_ = local_planner;  
}

void MoveBase::doWork()
{
  global_planner_->run();
  local_planner_->run();
}
// plugin.h
/* 模板方法模式的插件类 */
#ifndef TEMPLATE_METHOD_PLUGIN_H_
#define TEMPLATE_METHOD_PLUGIN_H_

#include "move_base.h"

// 全局路径规划使用Djkstra算法
class DijkstraPlanner:public BaseGlobalPlanner{
  public:
    void run();
};
// 局部路径规划使用Dwa算法
class DwaPlanner:public BaseLocalPlanner{
  public:
    void run();
};

#endif
// plugin.cc
/* 模板方法模式的插件类 */
#include <iostream>
#include "plugin.h"

void DijkstraPlanner::run(){
  std::cout<<"run Dijkstra algorithm..."<<std::endl;
}

void DwaPlanner::run(){
  std::cout<<"run DWA algorithm..."<<std::endl;
}

讨论

    模板方法模式适合于处理多个类之间具备相似的处理流程,只有少量不同的情况。在父类中,将这些相似处理流程做成模板,将不同的部分做成虚函数;在子类中,通过重载这些虚函数即可以避免重复编写相同代码。
    当子类过多时(例如:有100中全局路径规划算法),此时需要编写100个子类。此时,类的管理将变得麻烦,一个可能的解决办法是使用简单工厂模式来管理这100个子类。

Reference

    [1] 大话设计模式的第十章 部分参考了这里

posted on 2018-06-09 17:04  深蓝e  阅读(393)  评论(0编辑  收藏  举报

导航