设计模式(12) - Template模板方法模式

来源:互联网 发布:淘宝怎么打印发货清单 编辑:程序博客网 时间:2024/05/16 12:50

  1. Intent

  模板方法模式定义了某个操作中所用算法的框架,而把算法的具体实现步骤推迟到了子类中。这样,模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。
  这个模式就是用于创建一个算法模板的。那么什么是模板?
  它只是一个方法,一个将算法定义为一系列操作步骤的方法。这些步骤中的一个或者多个会被定义为抽象接口,子类去实现它。这就确保了当子类去实现具体步骤时,算法的结构不会被更改。

  2. UML classes

template_diagram
  参考上面图表:

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

  3. Example A

//template.h#ifndef _TEMPLATE_H_#define _TEMPLATE_H_#include <iostream>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"<<endl;}virtual void hook(){}};class ConcreteClassA:public AbstractClass{public:void primitiveOperation1(){cout<<"primitiveOp1 A"<<endl;}void primitiveOperation2(){cout<<"primitiveOp2 A"<<endl;}};class ConcreteClassB:public AbstractClass{public:void primitiveOperation1(){cout<<"primitiveOp1 B"<<endl;}void primitiveOperation2(){cout<<"primitiveOp2 B"<<endl;}void hook(){cout<<"hook B"<<endl;}};}}#endif//main.cpp#include "template.h"using namespace ShltshDesignPatterns::Template;int main(){ConcreteClassA ca;ConcreteClassB cb;ca.templateMethod();cb.templateMethod();system("pause");return 0;}
  运行结果:
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() {}

  4. Example B

  下面的这个例子中,有两个具体类,继承自OperationTemplate类,这个父类提供了3个接口:read_input(), write_output, 以及 operate()。两个子类在共用这些接口的同时,各自i实现了不同的操作。这就是模板方法模式所能提供的能力。
//template.h#ifndef _TEMPLATE_H_#define _TEMPLATE_H_#include<iostream>#include<algorithm>#include<cassert>#include<iterator>#include<list>#include<map>#include<sstream>#include<string>#include<utility>using namespace std;namespace ShltshDesignPatterns{namespace Template{class OperationTemplate{public:typedef std::map<std::string, std::string> 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<int> 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<int>(out, " "));output.insert(std::make_pair(std::string("result"), out.str()));}private:std::list<int> mList;};}}#endif//main.cpp#include "template.h"using namespace ShltshDesignPatterns::Template;int main(){  map<string, string> 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 . . .

0 0
原创粉丝点击