设计模式 22
- 创建型模式(5):工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式
- 结构型模式(7):适配器模式、桥接模式、组合模式、装饰者模式、外观模式、享元模式、代理模式
- 行为型模式(11):责任链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式、访问者模式
文章目录
- [设计模式 22](#设计模式 22)
-
- [模板方法模式(Template Method Pattern)](#模板方法模式(Template Method Pattern))
-
- [1 定义](#1 定义)
- [2 结构](#2 结构)
- [3 示例代码](#3 示例代码)
- [4 特点](#4 特点)
- [5 适用场景](#5 适用场景)
- [6 总结](#6 总结)
模板方法模式(Template Method Pattern)
1 定义
模板方法模式通过在基类中定义一个模板方法,该方法封装了一个算法的固定步骤,然后允许子类实现或重写这些步骤。这样,子类可以定制算法的具体行为,而无需改变算法的整体结构。
2 结构
模板方法模式包含以下角色:
- 抽象类(AbstractClass): 定义模板方法和算法的骨架。模板方法按照固定的步骤调用抽象方法或具体方法。
- 具体类(ConcreteClass): 继承自抽象类,实现或重写抽象方法,定义算法的具体步骤。
UML 类图
scss
+---------------------------+
| AbstractClass |
+---------------------------+
| + TemplateMethod(): void |
| + Step1(): void |
| + Step2(): void |
| - Step3(): void |
+---------------------------+
^
|
+-------------------+
| ConcreteClass |
+-------------------+
| - Step3(): void |
+-------------------+
3 示例代码
假设我们要制作一杯饮料,制作的过程包括煮水、冲泡、倒入杯中、添加配料等步骤。咖啡和茶是两种不同的饮料,它们在制作过程中的步骤基本相同,但在某些步骤上有所不同。我们可以使用模板方法模式来实现这个场景。
抽象类
csharp
// 抽象类 - 饮料制作过程
public abstract class Beverage
{
// 模板方法
public void PrepareRecipe()
{
BoilWater();
Brew();
PourInCup();
AddCondiments();
}
// 具体方法 - 煮水
private void BoilWater()
{
Console.WriteLine("Boiling water");
}
// 抽象方法 - 冲泡
protected abstract void Brew();
// 具体方法 - 倒入杯中
private void PourInCup()
{
Console.WriteLine("Pouring into cup");
}
// 抽象方法 - 添加配料
protected abstract void AddCondiments();
}
具体类
csharp
// 具体类 - 茶
public class Tea : Beverage
{
protected override void Brew()
{
Console.WriteLine("Steeping the tea");
}
protected override void AddCondiments()
{
Console.WriteLine("Adding lemon");
}
}
// 具体类 - 咖啡
public class Coffee : Beverage
{
protected override void Brew()
{
Console.WriteLine("Dripping coffee through filter");
}
protected override void AddCondiments()
{
Console.WriteLine("Adding sugar and milk");
}
}
客户端代码
csharp
class Program
{
static void Main(string[] args)
{
Beverage tea = new Tea();
tea.PrepareRecipe(); // 制作茶
Console.WriteLine();
Beverage coffee = new Coffee();
coffee.PrepareRecipe(); // 制作咖啡
}
}
运行结果
plaintext
Boiling water
Steeping the tea
Pouring into cup
Adding lemon
Boiling water
Dripping coffee through filter
Pouring into cup
Adding sugar and milk
在这个例子中,Beverage
是抽象类,定义了一个模板方法 PrepareRecipe()
,它包含了制作饮料的固定步骤。这些步骤中,有些是具体实现的(如 BoilWater()
和 PourInCup()
),而有些是抽象方法,由子类 Tea
和 Coffee
来实现(如 Brew()
和 AddCondiments()
)。客户端代码可以使用不同的具体类来制作不同的饮料,而不需要关心具体的实现细节。
4 特点
-
优点:
-
代码复用: 将通用的算法步骤封装到基类中,子类只需要实现差异化的部分,减少了重复代码。
-
扩展性强: 子类可以根据需要重写或扩展某些步骤,增加算法的灵活性。
-
控制算法结构: 父类定义了算法的骨架,确保了算法的整体结构不被子类破坏。
-
-
缺点:
-
增加代码复杂性: 由于引入了继承关系和抽象方法,可能会使代码结构变得复杂。
-
对子类的依赖: 父类依赖子类来实现某些步骤,可能导致子类必须实现某些方法,即使这些方法在特定情况下并不需要。
-
5 适用场景
- 多个类有相似的操作步骤: 当多个类的操作步骤大致相同时,可以使用模板方法模式将相同的部分提取到抽象类中。
- 算法需要多个步骤: 当算法需要分解为多个步骤,并且这些步骤中有些是固定的,有些是可变的,可以使用模板方法模式。
- 控制算法的流程: 当需要确保算法的某些步骤必须按照一定的顺序执行时,可以使用模板方法模式。
6 总结
模板方法模式通过将通用的算法步骤封装到抽象类中,允许子类重写或扩展特定的步骤,实现了算法的复用和扩展。它确保了算法的整体结构不被破坏,同时为子类提供了灵活性。在多个类具有相似的操作步骤时,模板方法模式是一种非常有效的设计模式。