[UE5 设计模式] 模板模式Template Pattern


参考材料
1. 【UE4 设计模式】策略模式 Strategy Pattern
2. 模板模式

1. 概述

1.1 描述

$\cdot$ 在模板模式(Template Pattern) 中, 一个抽象类公开定义了执行它的方法的方式/ 模板. 它的子类可以按需要重写方法实现, 但调用将以抽象类中定义的方式进行. 这种类型的设计模式属于行为型模式.

1.2 套路

$\cdot$ 实现方式:
$\\$ 1) 定义抽象父类: 包含模板方法和一些抽象方法或具体方法.
$\\$ 2) 实现子类: 继承抽象父类并实现抽象方法, 不改变算法结构.

$\cdot$ 关键代码:
$\\$ 1) 模板方法: 在抽象父类中定义, 调用抽象方法和具体方法.
$\\$ 2) 抽象方法: 由子类实现, 代表算法的可变部分.
$\\$ 3) 具体方法: 在抽象父类中实现, 代表算法的不变部分.

$\cdot$ 结构:
$\\$ 包含的几个主要角色:
$\\$ 1) 抽象父类(Abstract Class): 定义了模板方法和一些抽象方法或具体方法.
$\\$ 2) 具体子类(Concrete Classes): 继承自抽象父类, 并实现抽象方法.
$\\$ 3) 钩子方法(Hook Method)(可选): 在抽象父类中定义, 可以被子类重写, 以影响模板方法的行为.
$\\$ 4) 客户端(Client)(可选): 使用抽象父类和具体子类, 无需关心模板方法的细节.

1.3 使用场景

$\cdot$ 当存在一些通用的方法, 可以在多个子类中共用时.

1.4 优缺点

$\cdot$ 优点:
$\\$ 1) 封装不变部分: 算法的不变部分被封装在父类中.
$\\$ 2) 扩展可变部分: 子类可以扩展或修改算法的可变部分.
$\\$ 3) 提取公共代码: 减少代码重复, 便于维护.

$\cdot$ 缺点:
$\\$ 1) 类数目增加: 每个不同的实现都需要一个子类, 可能导致系统庞大.

2. UE5实践

我们将创建一个定义操作的FGame抽象类, 其中, 模板方法设置为final, 这样它就不会被重写. FCricket和FFootball是扩展了FGame的实体类, 它们重写了抽象类的方法.
$\\$ 我们使用FGame来演示模板模式的用法.

2.1 步骤1

创建一个抽象类, 它的模板方法被设置为final.


#pragma once


class FGame 
{
	virtual void Initialize() = 0;

	virtual void StartPlay() = 0;

	virtual void EndPlay() = 0;

	// 模板
	virtual void Play() final
	{
		// 初始化游戏
		Initialize();

		// 开始游戏
		StartPlay();

		// 结束游戏
		EndPlay();
	}
};

2.2 步骤2

创建扩展了上述类的实体类.


#pragma once

#include "Game.h"
#include "CoreMinimal.h"


class FCricket final : public FGame
{
	virtual void EndPlay() override
	{
		UE_LOG(LogTemp, Log, TEXT("Cricket Game Finished!"));
	}

	virtual void Initialize() override
	{
		UE_LOG(LogTemp, Log, TEXT("Cricket Game Initialized! Start playing."));
	}

	virtual void StartPlay() override
	{
		UE_LOG(LogTemp, Log, TEXT("Cricket Game Started. Enjoy the game!"));
	}
};


#pragma once

#include "Game.h"
#include "CoreMinimal.h"


class FFootball final : public FGame
{
	virtual void EndPlay() override
	{
		UE_LOG(LogTemp, Log, TEXT("Football Game Finished!"));
	}

	virtual void Initialize() override
	{
		UE_LOG(LogTemp, Log, TEXT("Football Game Initialized! Start playing."));
	}

	virtual void StartPlay() override
	{
		UE_LOG(LogTemp, Log, TEXT("Football Game Started. Enjoy the game!"));
	}
};

2.3 步骤3

使用FGame的模板方法Play()来演示游戏的定义方式.


#include "Circket.h"
#incluce "Football.h"


int main()
{
	FGame* GameInstance = new FCricket();
	GameInstance->Play();
	delete GameInstance;

	GameInstance = new FFootball();
	GameInstance->Play();
	delete GameInstance;

	GameInstance = nullptr;
	return 0;
}

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注