Bootstrap

设计模式学习[9]---模板方法模式

前言

大型的C++项目,都会用到很多模板,C++中关于模板的书也不少,那么在设计模式中的模板模式和C++的模板又有什么区别呢?模板和上篇的原型又有哪些不同?

这篇博客就详细介绍一下。

1.原理阐述

1.1 C++模板说明

在C++中,模板称之为 t e m p l a t e template template。一般把一系列相同定义、相同业务逻辑但类型不同等情况的函数提取出来,作为一个模板,其中共性的部分作为模板。

比如一个比较函数,有int类型的比较函数和float类型的比较函数,如果A比B大则返回1,否则返回-1
下面是一个不严谨的例子,简单看看

template<typename T>
int m_funCompare(const T &A,const T &B)
{
	if(A>B)return 1;
	if(A<B)return -1;
	return 0;
}

这里我们把比较的过程抽离出来,业务逻辑都是一致的,只是比较的参数不同,所以用模板无疑节省了不少工作量。

1.2 设计模式模板

对于模板方法模式,和C++的模板有点类似,但又不完全相同。
书中的定义如下:

模板方法模式:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

讲下个人理解:
就是业务流程基本一致,但是在面向对象开发的时候,不同子类的对象对于父类对象的某个操作,有不同的实现方式。其实就是多态的一种体现。

比如我们说鸟会鸣叫,那么麻雀和布谷鸟的鸣叫肯定是不一样的,但是在面向对象开发的时候,我们统一是通过去调用“鸣叫”这个接口(当然如果你硬要用麻雀去调用鸣叫接口,我也没话说),那么我们能否认为这个调用过程其实是固定的,可以认为它就是一种模板。鸟这个父类下面的子类,针对这个接口做不同的实现,但是子类并没有改变这个调用的一个流程。

所以模板方法模式在实现上就是,用父类包装一层相对固定的流程/算法/业务,用子类继承,在子类上面做一些特定的操作。

2.举例

下面将鸟类的例子做一下简单的代码实现

#include<iostream>
using namespace std;
class Bird
{
public:
	void start(){cout<<"鸟叫开始"<<endl;}
	virtual void sing()=0;
	void end(){cout<<"鸟叫结束"<<endl;}
	void action()
	{
		start();
		sing();
		end();
	}
};
class sparrow : public Bird
{
	void sing(){cout<<""叽叽喳喳"<<endl;}
};
class cuckoo: public Bird
{
	void sing(){cout<<""布谷布谷"<<endl;}
};
int main()
{
	Bird* bird1=new sparrow();
	Bird* bird2=new cuckoo();
	bird1->action();
	bird2->action();
}

上面的程序打印内容如下:

鸟叫开始
叽叽喳喳
鸟叫结束
鸟叫开始
布谷布谷
鸟叫结束

这个例子中我把共性的业务流程/算法,放到父类Bird中,不同的子类(鸟),重新实现某个具体的步骤,这里是鸟叫。

3.和原型模式的区别

原型模式
原型模式更倾向于是对象创建,它属于创建型的设计模式。重点是在于对象的创建初始化。
而模板类型,是提取共有的一些过程,它的重点在于过程。模板方法模式它实际上是属于行为型模式。
两者在名字上听起来有点类似,模板,原型,原型不就是类似于一个模板,模板不就是一个原型吗。但是具体的运用场景还是不太一样的,这里要注意。

总结

我们在开发的时候遇到一些共性的业务流程,如果一味的用最简单的逻辑去做,往往是代码量大了,但是重复,冗余。
代码质量很低,同时显得自己的水平也不高。模板方法模式是一种代码复用技术,遇到这种大量重复冗余的情况,多想想设计模式,用多态的思想去处理问题,代码水平更上一层楼。

;