重温设计模式--模板方法模式

news/2024/12/25 1:24:34 标签: 设计模式, 模板方法模式, java

文章目录

  • 一、模板方法模式概述
  • 二、模板方法模式UML图
  • 三、优点
    • 1代码复用性高
    • 2可维护性好
    • 3扩展性强
  • 四、缺点
  • 五、使用场景
  • 六、C++ 代码示例1
  • 七、 C++ 代码示例2

一、模板方法模式概述

定义:定义一个操作中的算法骨架,而降一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
定义:模板方法模式是一种行为设计模式。它在一个抽象类中定义了一个算法的骨架(模板方法),将一些步骤的实现延迟到子类中。模板方法定义了算法的步骤顺序,子类可以根据自身的需求重写其中的某些步骤,而整体算法的流程结构保持不变。

二、模板方法模式UML图

在这里插入图片描述

三、优点

1代码复用性高

在抽象类中定义的模板方法和一些通用步骤可以在多个子类中复用,避免了代码的重复编写。例如,在一个游戏开发中,游戏角色的移动和攻击行为可能有共同的流程结构,通过模板方法模式可以把这个共同的流程提取出来,不同类型的角色(如战士、法师)可以复用这个流程,只需要实现自己特定的移动和攻击方式即可。

2可维护性好

由于算法的结构在抽象类中已经定义好,当需要对整体算法流程进行修改时,只需要在抽象类中修改模板方法的实现,而不需要在每个具体子类中进行修改。比如,在一个文件读取处理的系统中,如果要改变文件读取后的处理流程顺序,只需要在抽象的文件处理类的模板方法中调整步骤顺序,而各个具体文件类型(如文本文件、二进制文件)的处理子类可以保持不变。

3扩展性强

可以很方便地通过创建新的子类来扩展系统功能。新的子类可以选择性地重写模板方法中的步骤,以实现新的行为。例如,在一个图形绘制系统中,已经有了绘制基本图形(如圆形、矩形)的类,当需要添加一种新的图形(如三角形)时,只需要创建一个新的子类,重写绘制图形的具体步骤,而整体的图形绘制流程(如打开画布、选择颜色、绘制图形、关闭画布)可以复用已有的模板方法。

四、缺点

可能会导致类的层次结构复杂:因为需要创建抽象类和多个子类来实现模板方法模式,所以如果设计不当,可能会导致类的层次结构过于复杂,增加代码的理解和维护难度。
不符合开闭原则的部分情况:虽然模板方法模式在一定程度上符合开闭原则(对扩展开放,对修改关闭),但如果要对模板方法本身进行修改,可能会影响到所有的子类。例如,在模板方法中增加或删除一个步骤,可能需要在所有子类中进行相应的调整。

五、使用场景

多个子类有共同的算法流程,但某些步骤的实现细节不同:比如在一个订单处理系统中,线上订单和线下订单的处理流程都包括接收订单、处理支付、安排发货等步骤,但线上订单和线下订单在处理支付和安排发货的具体方式上可能不同。
需要控制子类的扩展行为,保证算法结构的稳定性:例如在一个编译器的语法分析模块中,不同编程语言的语法分析都有一个基本的流程,如词法分析、语法树构建、语义检查等步骤。通过模板方法模式可以定义这个基本流程,让不同编程语言的语法分析子类在这个框架内进行扩展,同时保证整体的语法分析算法结构不变。

六、C++ 代码示例1

以下是一个简单的 C++ 代码示例,模拟一个游戏角色攻击的模板方法模式。假设有一个抽象的 GameCharacter 类,定义了游戏角色攻击的模板方法,还有两个具体的角色类 Warrior 和 Mage,它们分别重写了攻击的具体实现方式。

#include <iostream>
#include <string>

// 抽象游戏角色类
class GameCharacter 
{
public:
	// 模板方法,定义了攻击的算法流程
	void attack()
	{
		std::cout << "The character is preparing to attack." << std::endl;
		performAttack();
		std::cout << "The character has finished the attack." << std::endl;
	}
protected:
	// 抽象方法,由子类实现具体的攻击方式
	virtual void performAttack() = 0;
};

// 战士角色类
class Warrior : public GameCharacter
{
protected:
	void performAttack() override 
	{
		std::cout << "1" << std::endl;
		std::cout << "2" << std::endl;
		std::cout << "The warrior swings his sword." << std::endl;
	}
};

// 法师角色类
class Mage : public GameCharacter
{
protected:
	void performAttack() override 
	{
		std::cout << "The mage casts a spell." << std::endl;
		std::cout << "888" << std::endl;
		std::cout << "777" << std::endl;
	}
};
int main() 
{
	Warrior warrior;
	Mage mage;
	std::cout << "Warrior's attack:" << std::endl;
	warrior.attack();
	std::cout << "Mage's attack:" << std::endl;
	mage.attack();
	char t;
	std::cin>>t;
	return 0;
}

在上述代码中:
首先定义了抽象类 GameCharacter,它有一个公共的方法 attack,这就是模板方法。在 attack 方法中,定义了攻击行为的算法流程,包括准备攻击、执行具体的攻击动作(通过调用纯虚函数 performAttack)和完成攻击。performAttack 函数是一个纯虚函数,需要在子类中实现。
然后定义了两个具体的子类 Warrior 和 Mage,它们都继承自 GameCharacter。在这两个子类中,分别重写了 performAttack 函数,实现了战士挥舞剑和法师释放法术的不同攻击方式。
在 main 函数中,创建了 Warrior 和 Mage 类型的对象,并分别调用它们的 attack 方法,这样就会按照模板方法中定义的流程执行攻击行为,每个角色会执行自己特有的攻击动作。

七、 C++ 代码示例2

#include<iostream>
using namespace std;

//抽象类,
//在父类中定义操作的算法骨架,而具体的实现由子类完成
class resume
{
protected:
	virtual void setedu(){}
	virtual void setage(){}
	virtual void setexp(){}
public:
	void setinformation()//骨架
	{
		setedu();
		setage();
		setexp();
	}
};
//子类
class xiaoming:public resume
{
	void setedu(){cout<<"清华大学"<<endl;}//具体实现
	void setage(){cout<<"19岁"<<endl;}//具体实现
};
class xiaoli:public resume
{
	void setedu(){cout<<"北京大学"<<endl;}//具体实现
	void setage(){cout<<"10岁"<<endl;}//具体实现
	void setexp(){cout<<"腾讯科技"<<endl;}
};
int main()
{
	resume *s1 = new xiaoming();
	s1->setinformation();
	cout<<endl<<endl;
	resume *s2 = new xiaoli();
	s2->setinformation();
	char t;
	std::cin>>t;
	return 0;
}


http://www.niftyadmin.cn/n/5798397.html

相关文章

R9000P键盘失灵解决办法

问题描述 突然&#xff0c;就是很突然&#xff0c;我买的R9000P 2024不到三个月&#xff0c;键盘突然都不能用了&#xff0c;是所有键盘按键都无效的那种。&#xff08;可以使用外接键盘&#xff09; 解决办法 我本科室友说的好哈&#xff0c;全坏全没坏。 &#xff08;该解…

ssr实现方案

目录 序言 一、流程 二、前端要做的事情 三、节点介绍 四、总结 序言 本文不是详细的实现过程&#xff0c;是让你最快最直接的理解ssr的真正实现方法&#xff0c;有前端经验的同学&#xff0c;能够很好的理解过程&#xff0c;细节根据具体项目实现 一、前端要做的事情 1.…

AWTK-WEB 快速入门(2) - JS 应用程序

AWTK 可以使用相同的技术栈开发各种平台的应用程序。有时我们需要使用 Web 界面与设备进行交互&#xff0c;本文介绍一下如何使用 JS 语言开发 AWTK-WEB 应用程序。 用 AWTK Designer 新建一个应用程序 先安装 AWTK Designer&#xff1a; https://awtk.zlg.cn/web/index.html…

ubuntu开机进入initramfs状态

虚拟机卡死成功起后进入了initramfs状态&#xff0c;可能是跟文件系统有问题或者检索不到根文件系统&#xff0c;或者是配置错误&#xff0c;系统磁盘等硬件问题导致 开机后进入如下图的界面&#xff0c; 文中有一条提示 要手动fsck 命令修复 /dev/sda1 命令如下 fsck /de…

查询Elasticsearch索引刷新间隔

要查询 Elasticsearch 索引的刷新间隔&#xff08;refresh_interval&#xff09;&#xff0c;你可以使用以下方法&#xff1a; 1. 使用 GET 请求查询索引设置 你可以通过 GET 请求获取索引的设置信息&#xff0c;其中包括 refresh_interval 的值。 示例命令 GET /your_inde…

Retrofit源码分析:动态代理获取Api接口实例,解析注解生成request,线程切换

目录 一&#xff0c;Retrofit的基本使用 1.定义api接口 2.创建Retrofit实例 3.获取api接口实例发起请求 二&#xff0c;静态代理和动态代理 1&#xff0c;静态代理 2&#xff0c;动态代理 三&#xff0c;动态代理获取Api接口实例 四&#xff0c;解析接口方法注解&…

thinkphp8自带分页bootstrap

tp8引用的是bootstrap3.4.1这个版本&#xff1b; 前端结构&#xff1a; <ul class"pagination"><li><a href"/index.php?page4"></a></li><li><a href"/index.php?page1">1</a></li>…

如何在K8S集群中查看和操作Pod内的文件?

文章目录 一、理解Kubernetes中的Pod二、查看Pod内的文件三、操作Pod内的文件四、高级技巧五、常见问题与解决方案 在Kubernetes&#xff08;K8s&#xff09;集群中&#xff0c;Pod是最小的可部署单元&#xff1b; 一、理解Kubernetes中的Pod 在Kubernetes中&#xff0c;Pod是…