C++设计模式——模版方法

前言

临近毕业,很多人都会到人才网发布简历以寻求符合自己要求的岗位。登陆人才网,系统会给我们提供一份统一的模板,我们只需要按照要求填写个人信息、教育背景、工作经历、项目经验等内容就可以了。虽然大家都是使用相同的模板,但每个人填写的求职信息各不相同,简历也就各不一样。在设计模式中,也存在类似的一种模式。实现某个功能需要多个步骤,其中有些步骤是固定的,有些步骤是不固定的,存在可变性,提供一个模板方法来定义这些步骤的执行次序,而通过其子类来覆盖某些步骤,从而使得相同的算法框架可以有不同的执行结果,称之为模板方法模式。

1、模板方法模式

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

    模板方法模式是一种基于继承的代码复用技术,它是一种类行为型模式

    模板方法模式是结构最简单的行为型设计模式,在其结构中只存在父类与子类之间的继承关系。通过使用模板方法模式,可以将一些复杂流程的实现步骤封装在一系列基本方法中,在抽象父类中提供一个称之为模板方法的方法来定义这些基本方法的执行次序,而通过其子类来覆盖某些步骤,从而使得相同的算法框架可以有不同的执行结果。模板方法模式提供了一个模板方法来定义算法框架,而某些具体步骤的实现可以在其子类中完成。

    模板方法模式结构比较简单,其核心是抽象类和其中的模板方法的设计。

 模板方法模式结构图

    (1) AbstractClass(抽象类)在抽象类中定义了一系列基本操作(PrimitiveOperations),这些基本操作可以是具体的,也可以是抽象的,每一个基本操作对应算法的一个步骤,在其子类中可以重定义或实现这些步骤。同时,在抽象类中实现了一个模板方法(Template Method),用于定义一个算法的框架,模板方法不仅可以调用在抽象类中实现的基本方法,也可以调用在抽象类的子类中实现的基本方法,还可以调用其他对象中的方法。

    (2) ConcreteClass(具体子类)它是抽象类的子类,用于实现在父类中声明的抽象基本操作以完成子类特定算法的步骤,也可以覆盖在父类中已经实现的具体基本操作。

    在实现模板方法模式时,开发抽象类的软件设计师和开发具体子类的软件设计师之间可以进行协作。一个设计师负责给出一个算法的轮廓和框架,另一些设计师则负责给出这个算法的各个逻辑步骤。实现这些具体逻辑步骤的方法即为基本方法,而将这些基本方法汇总起来的方法即为模板方法,模板方法模式的名字也因此而来。下面将详细介绍模板方法和基本方法:

    1. 模板方法

    一个模板方法是定义在抽象类中的、把基本操作方法组合在一起形成一个总算法或一个总行为的方法。这个模板方法定义在抽象类中,并由子类不加以修改地完全继承下来。模板方法是一个具体方法,它给出了一个顶层逻辑框架,而逻辑的组成步骤在抽象类中可以是具体方法,也可以是抽象方法。

    2. 基本方法

    基本方法是实现算法各个步骤的方法,是模板方法的组成部分。基本方法又可以分为2种:抽象方法、具体方法。

    (1) 抽象方法:一个抽象方法由抽象类声明、由其具体子类实现。

    (2) 具体方法:一个具体方法由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承。


2、SIM9000短信接收模块的设计与实现

    我们平常使用的移动手机,很多都是使用SIM9000来实现通信功能。而对于短信接收模块,接收到信息实际上是经过编码的PDU串,得把接收到的PDU串进行译码后,才是我们看到的真正短信内容。例如:当对方发送 "您好,北京欢迎您" ,我们接收到的是经过编码后的PDU字符串"031648523486D596D5F8054901"。因此,得对PDU字符串进行译码,译码之后显示"您好,北京欢迎您"。


SIM9000短信PDU协议格式

    本例中,为了突出模板方法模式的思想,将简化实现过程。对接收的短信,只关心发送人是谁、接收的数据长度、以及接收的数据内容。其它的信息不做处理。我们发现,对PDU字符串进行译码有三个基本操作,接收短信对短信内容进行译码显示译码之后的短信内容。接收短信和显示译码之后的内容是两个固定的基本方法,而对短信进行译码是一个不固定的基本方法,可以使用(7转8算法)对PDU串进行译码,也可以使用(8转7算法)进行译码操作。

    请使用模板方法模式实现对PDU字符串进行7转8译码,8转7两种译码。(具体两种译码细节读者不需要关心,只需要关注模板方法模式的思想就可以了)。

    对短信PDU串进行译码实现代码如下:

#ifndef _DECRYPT_H_
#define _DECRYPT_H_

#include <iostream>
#include <string>
using namespace std;


//接收到的短消息
class ShortMsg
{
public:
	//基本方法: 接收编码后的消息
	void RecvMsg()
	{
		cout << "接收编码后的: <发送人> 字段内容" << endl;
		cout << "接收编码后的: <消息长度> 字段内容" << endl;
		cout << "接收编码后的: <数据内容> 字段内容" << endl;
		cout << "------------------------------------------" << endl << endl;
	}

	//基本方法: 译码消息
	virtual void DecryptMsg() = 0;

	//基本方法: 显示译码后的消息
	void DisplayMsg()
	{
		cout << "显示译码后的: <发送人> 字段内容" << endl;
		cout << "显示译码后的: <消息长度> 字段内容" << endl;
		cout << "显示译码后的: <数据内容> 字段内容" << endl;
		cout << "------------------------------------------" << endl << endl;
	}

	//模板方法: 执行译码操作
	void ExcuteDecrypt()
	{
		RecvMsg();
		DecryptMsg();
		DisplayMsg();
	}
};


//7转8译码
class SevenTo8Decrypt : public ShortMsg
{
public:
	//7转8译码
	void DecryptMsg()
	{
		cout << "对编码后的: <发送人> 字段内容进行7转8译码" << endl;
		cout << "对编码后的: <消息长度> 字段内容进行7转8译码" << endl;
		cout << "对编码后的: <数据内容> 字段内容进行7转8译码" << endl;
		cout << "------------------------------------------" << endl << endl;
	}
};



//8转7译码
class EightTo7Decrypt : public ShortMsg
{
public:
	//8转7译码
	void DecryptMsg()
	{
		cout << "对编码后的: <发送人> 字段内容进行8转7译码" << endl;
		cout << "对编码后的: <消息长度> 字段内容进行8转7译码" << endl;
		cout << "对编码后的: <数据内容> 字段内容进行8转7译码" << endl;
		cout << "------------------------------------------" << endl << endl;
	}
};


#endif

ShortMsg是抽象的短消息类,包含RecvMsg、DecryptMsg、DisplayMsg三个基本方法。ExcuteDecrypt是模板方法,用于把这三个基本方法按照一定的顺序组合起来。SevenTo8Decrypt和EightTo7Decrypt是具体的译码算法类,实现抽象类中声明的译码操作接口DecryptMsg。

    测试文件实现代码如下:

#include <iostream>
#include "Decrypt.h"
using namespace std;

int main()
{
	//对接收到的消息进行7转8译码
	ShortMsg * p7To8Decrypt = new SevenTo8Decrypt();
	p7To8Decrypt->ExcuteDecrypt();
		
	delete p7To8Decrypt;

	return 0;
}

编译并执行,程序结果如下:


    如果需要使用其它的译码方法,只需要从抽象短消息类派生一个子类,实现父亲中声明的译码接口。无需修改之前的代码。符合"开放封闭原则"。


3、模板方法模式总结

    模板方法模式是基于继承的代码复用技术,将公共的方法(一般都是不变的部分)封装到父类中,而可变的部分可以通过继承来继续扩展,把变化部分和不变化部分分隔开。一方面能够实现代码复用,另一方面便于维护,它体现了面向对象的诸多重要思想,如封装变化思想"找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。换句话说,如果每次新的需求一来,都会使某些方面的代码发生变化,那么可以确定,这部分的代码需要被抽象出来,和其他稳定的代码有所区别"。模板方法把一些基本方法按照一定的顺序组合起来,实现某个功能。如果不使用模板方法把这些基本方法按照一定的顺序给组合起来,则子类可以使用任意的顺序组合这些基本方法,导致程序逻辑混乱,无法控制。模式广泛应用于框架设计中,以确保通过父类来控制处理流程的逻辑顺序。

1.模板方法模式的主要优点

    (1) 在父类中形式化地定义一个算法,而由它的子类来实现细节的处理,在子类实现详细的处理算法时并不会改变算法中步骤的执行次序。

    (2) 模板方法模式是一种代码复用技术,它在类库设计中尤为重要,它提取了类库中的公共行为,将公共行为放在父类中(不变的部分),而通过其子类来实现不同的行为(异变部分),它鼓励我们恰当使用继承来实现代码复用。

    (3) 可实现一种反向控制结构,通过子类覆盖父类的钩子方法来决定某一特定步骤是否需要执行。

    (4) 在模板方法模式中可以通过子类来覆盖父类的基本方法,不同的子类可以提供基本方法的不同实现,更换和增加新的子类很方便,符合单一职责原则和开闭原则。

2.模板方法模式的主要缺点

    (1)需要为每一个基本方法的不同实现提供一个子类,如果父类中可变的基本方法太多,将会导致类的个数增加,系统更加庞大,设计也更加抽象。

3.模板方法模式的具体应用

    (1)在游戏角色中,存在魔鬼、天使、英雄等角色。这些角色都包含相同的建造过程(建造头、脚、外观等),而每一个游戏角色建造方法各不相同。

    (2)需要将某些数据导出到TXT文本、数据库、XML中。存在相同的过程,获取数据,导出操作、查找已经导出的数据。

    (3)数据结构中的排序算法:定义一个抽象排序类,具体子类如快速排序、选择排序、冒泡排序等实现基类中的排序算法。

    (4)对数据库进行查询操作:定义一个基类,包含连接数据库、查询数据、关闭连接等方法。不同的表,查询操作是不一样的。可以定义具体的查询类,继承于基类,实现基类中查询接口,用于对不同的表进行查询操作。

    (5)对于一些加密算法,包含许多按照某些顺序执行的操作。而具体不同的加密算法,某个操作执行结果不同。

    (6)银行部门采用的利息算法:活期账户和定期账户各使用不同的计算方法。

    (7)网上购物付款方式: 使用U顿则输入密码就可以付款。而使用短信验证支付,会弹出一个对话框,要求我们输入姓名、卡号、身份证号等信息。也就是说对于不同的支付方式,支付操作不同。

    (8)同样是登陆某个系统,普通用户登陆和管理员登陆,登陆后的界面存在某些差别。有些功能是普通用户不具有的。

    (9)在一些UI控件中,可以从基类派生一个新的控件,重写某些功能。例如:可以从Button类中继承一个子类,在子类中覆盖基类中的某些操作。
    (10)生活中模板: 求职简历;DNA双螺旋结构;鸟叔江南Style风靡全球的时候,广场舞大妈一步步分解动作,模仿鸟叔的舞姿;制作手机电脑等产品,需要按照某个过程来执行一系列操作;景德镇陶瓷的制作等。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值