目录
1.意图
模板方法模式定义了某个操作中所用算法的框架,而把算法的具体实现步骤推迟到了子类中。这样,模板方法使得子类可以在不改变算法结构的前提下,重新定义算法中的某些步骤。
这个模式就是用于创建一个算法模板的。那么什么是模板?
它只是一个方法,一个将算法定义为一系列操作步骤的方法。这些步骤中的一个或者多个会被定义为抽象接口,子类去实现它。这就确保了当子类去实现具体步骤时,算法的结构不会被更改。
2.UML类图
3.GOF角色说明
AbstractClass:包含了模板方法。模板方法中使用了操作的抽象版本。
ConcreteClasses:实现了抽象操作,当templateMethod()需要它们时,它们就会被调用到。
可能存在很多的ConcreteClasses类, 每一个类中都实现了模板方法所需要的所有操作集合。
模板方法利用primativeOperations来实现一个算法。这样可以和这些操作的具体实现进行解耦。
4.代码实现一
//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() {}
5.代码实现二
下面的这个例子中,有两个具体类,继承自OperationTemplate类,这个父类提供了3个接口:read_input(), write_output, 以及 operate()。
两个子类在共用这些接口的同时,各自实现了不同的操作。这就是模板方法模式所能提供的能力。
//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 . . .