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

目录

1.意图

2.UML类图

​3.GOF角色说明

4.代码实现一

5.代码实现二


1.意图

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

2.UML类图

template_diagram
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 . . .

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值