博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式(12) - Template模板方法模式
阅读量:4071 次
发布时间:2019-05-25

本文共 4629 字,大约阅读时间需要 15 分钟。

目录


1.意图

  模板方法模式定义了某个操作中所用算法的框架,而把算法的具体实现步骤推迟到了子类中。这样,模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。

  这个模式就是用于创建一个算法模板的。那么什么是模板?
  它只是一个方法,一个将算法定义为一系列操作步骤的方法。这些步骤中的一个或者多个会被定义为抽象接口,子类去实现它。这就确保了当子类去实现具体步骤时,算法的结构不会被更改。

2.UML类图

template_diagram
3.GOF角色说明

  AbstractClass:包含了模板方法。模板方法中使用了操作的抽象版本。

  ConcreteClasses:实现了抽象操作,当templateMethod()需要它们时,它们就会被调用到。
  可能存在很多的ConcreteClasses类, 每一个类中都实现了模板方法所需要的所有操作集合。
  模板方法利用primativeOperations来实现一个算法。这样可以和这些操作的具体实现进行解耦。

4.代码实现一

//template.h#ifndef _TEMPLATE_H_#define _TEMPLATE_H_#include 
using namespace std;namespace ShltshDesignPatterns { namespace Template { class AbstractClass { public: void templateMethod() { primitiveOperation1(); primitiveOperation2(); concreteOperation(); hook(); } virtual void primitiveOperation1()=0; virtual void primitiveOperation2()=0; void concreteOperation() { cout<<"Mandatory Operations for all ConcreteClasses"<

运行结果:

primitiveOp1 A
primitiveOp2 A
Mandatory Operations for all ConcreteClasses
primitiveOp1 B
primitiveOp2 B
Mandatory Operations for all ConcreteClasses
hook B
Press any key to continue . . .
  基于上面的结果,可以总结如下:
  1).函数templateMethod()定义了步骤的顺序,每个步骤由一个方法实现。
  2).下面的这两个原始操作必须在具体的子类中实现。
      virtual void primitiveOperation1() = 0;
      virtual void primitiveOperation2() = 0;
  3).下面的这个具体操作是在抽象类中定义的。这个方法没有定义成虚函数(virtual),这样子类就不能覆写(override)它。它可能被模板方法直接使用,或者子类使用。
      void concreteOperation() { cout<<"Mandatory Operations for all ConcreteClasses" << endl; }
  4).我们也可以创建具体方法,但是这些方法不做什么事情,称为hooks。子类可以自由选择是否覆写它们。
      virtual void hook() {}

5.代码实现二

  下面的这个例子中,有两个具体类,继承自OperationTemplate类,这个父类提供了3个接口:read_input(), write_output, 以及 operate()。

  两个子类在共用这些接口的同时,各自实现了不同的操作。这就是模板方法模式所能提供的能力。

//template.h#ifndef _TEMPLATE_H_#define _TEMPLATE_H_#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;namespace ShltshDesignPatterns{ namespace Template { class OperationTemplate { public: typedef std::map
Arguments; bool solve(const Arguments &input, Arguments &output) { assert(output.empty()); if(!read_input(input)) return false; if(!operate()) return false; write_output(output); return true; } protected: virtual bool read_input(const Arguments &input) = 0; virtual bool operate() = 0; virtual void write_output(Arguments &output)const = 0; }; class MathOperation:public OperationTemplate { public: MathOperation():mx(0),my(0),mOperation(0),mResult(0){ } private: bool read_input(const Arguments &input) { Arguments::const_iterator iter = input.find("x"); if(input.end() == iter) return false; std::istringstream in(iter->second); in >> mx; if(in.fail()) return false; iter = input.find("y"); if(input.end() == iter) return false; in.clear(); in.str(iter->second); in>>my; if(in.fail()) return false; iter=input.find("operation"); if(input.end()==iter || iter->second.size()!=1) return false; mOperation = iter->second[0]; return true; } bool operate() { switch (mOperation) { case '+': mResult = mx + my; break; case '-': mResult = mx - my; break; case '*': mResult = mx * my; break; case '/': if (0 == my) { return false; } mResult = mx / my; break; default: return false; } return true; } void write_output(Arguments &output) const { std::ostringstream out; out << mResult; output.insert(std::make_pair(std::string("result"), out.str())); } private: int mx,my,mResult; char mOperation; }; class ListOperation : public OperationTemplate { private: bool read_input(const Arguments &input) { mList.clear(); Arguments::const_iterator i = input.find("array"); if (input.end() == i) { return false; } std::istringstream in(i->second); typedef std::istream_iterator
T; std::copy(T(in), T(), std::back_inserter(mList)); if (!in.eof()) return false; return true; } bool operate() { mList.reverse(); return true; } void write_output(Arguments &output) const { std::ostringstream out; std::copy(mList.begin(), mList.end(), std::ostream_iterator
(out, " ")); output.insert(std::make_pair(std::string("result"), out.str())); } private: std::list
mList; }; }}#endif//main.cpp#include "template.h"using namespace ShltshDesignPatterns::Template;int main(){ map
myInput, myOutput; // 10 + 20 = 30 myInput.insert(make_pair("x", "10")); myInput.insert(make_pair("y", "20")); myInput.insert(make_pair("operation", "+")); MathOperation a; a.solve(myInput, myOutput); cout << myOutput["result"] << endl; myInput.clear(); myOutput.clear(); // 1 2 3 4 5 -> 5 4 3 2 1 myInput["array"] = "1 2 3 4 5"; ListOperation b; b.solve(myInput, myOutput); cout << myOutput["result"] << endl; system("pause"); return 0;}

运行结果:

30
5 4 3 2 1
Press any key to continue . . .

转载地址:http://xleji.baihongyu.com/

你可能感兴趣的文章
一个关于Http的请求头Expect
查看>>
最近用C#写Winform的一个心得
查看>>
PHP中日期相加减
查看>>
Ext中RowExpander数据刷新
查看>>
Ext中tabpanel对面板的添加
查看>>
Ext中的选择器
查看>>
自己设计的一个PHP的MVC framework
查看>>
ext中联动combo远程加载选中的解决
查看>>
ie下对于window.location.href的跳转时获取不到referer的,php中的路径包含有未定式的
查看>>
一段有用的jquery代码
查看>>
c#中队trunked的处理
查看>>
笔记本无线路由组件的局域网ping不通的问题
查看>>
php中require后的路径问题
查看>>
ext直接导出结果到excel
查看>>
combotree的总结
查看>>
最近小结
查看>>
大规模图像分类器的演化-Large-Scale Evolution of Image Classifiers-读后杂谈
查看>>
java对大文件的处理思路
查看>>
qt中的一个问题
查看>>
MFC编写的人民币大小写转换
查看>>