模板方法模式
本课属于 Coddy C# 学习旅程的“面向对象编程”单元。第 59 课,共 70 课。
模板方法模式是一种行为型模式,它在基类中定义算法的骨架,让子类可以重写特定步骤,而不改变整体结构。基类控制工作流程,派生类则自定义各个部分。
这种模式使用继承和抽象方法。基类包含一个“模板方法”,它会按顺序调用一系列步骤,其中一些步骤是抽象的,必须由子类实现:
public abstract class DataProcessor
{
// 模板方法:定义算法结构
public void Process()
{
ReadData();
ProcessData();
SaveData();
}
protected abstract void ReadData();
protected abstract void ProcessData();
protected virtual void SaveData() => Console.WriteLine("Saving to default location");
}
public class CsvProcessor : DataProcessor
{
protected override void ReadData() => Console.WriteLine("Reading CSV file");
protected override void ProcessData() => Console.WriteLine("Parsing CSV data");
}
public class JsonProcessor : DataProcessor
{
protected override void ReadData() => Console.WriteLine("Reading JSON file");
protected override void ProcessData() => Console.WriteLine("Parsing JSON data");
protected override void SaveData() => Console.WriteLine("Saving to cloud");
}每个子类都提供自己的实现,而基类负责强制执行操作顺序:
DataProcessor csv = new CsvProcessor();
csv.Process();
// 读取 CSV 文件
// 解析 CSV 数据
// 保存到默认位置
DataProcessor json = new JsonProcessor();
json.Process();
// 读取 JSON 文件
// 解析 JSON 数据
// 保存到云端当多个类共享相同的算法结构,但在具体步骤上有所不同时,模板方法模式就很适用。它将通用逻辑放在基类中,从而促进代码复用,同时通过可重写的方法保留灵活性。
挑战
简单让我们使用模板方法模式构建一个报告生成系统。不同类型的报告(例如销售报告和库存报告)有相同的整体结构:它们都需要收集数据、设置格式并输出结果,但每种报告类型处理这些步骤的方式各不相同。
你需要将代码分成三个文件:
ReportGenerator.cs:在Reporting命名空间中创建一个抽象的ReportGenerator类。这个基类通过名为Generate()的模板方法定义报告生成算法的框架。该方法应按顺序调用三个步骤:GatherData()、FormatReport()和OutputReport()。将GatherData()和FormatReport()设为抽象方法(每种报告类型都会以不同方式实现它们),而OutputReport()应是一个带默认实现的虚方法,该实现会打印Sending to default printer。ConcreteReports.cs:在同一命名空间中创建两个继承自ReportGenerator的具体报告类:SalesReport:实现GatherData()并打印Collecting sales data from database,实现FormatReport()并打印Formatting as sales summaryInventoryReport:实现GatherData()并打印Scanning warehouse inventory,实现FormatReport()并打印Formatting as inventory list,并重写OutputReport()以打印Sending to warehouse manager
Program.cs:创建报告实例并生成报告,将所有内容整合起来。模板方法确保每份报告都遵循相同的三步流程,但每个步骤的具体行为会根据报告类型而变化。
你将收到一个输入:
- 报告类型:
sales或inventory
根据输入创建相应的报告生成器,并调用它的 Generate() 方法。
例如,如果输入是 sales,输出应为:
Collecting sales data from database
Formatting as sales summary
Sending to default printer如果输入是 inventory,输出应为:
Scanning warehouse inventory
Formatting as inventory list
Sending to warehouse manager注意,两种报告都遵循完全相同的算法结构(收集、设置格式、输出),但每个步骤的实现都经过了定制。SalesReport 使用默认的输出行为,而 InventoryReport 则重写了该行为。这展示了模板方法模式如何让你控制哪些步骤必须重写,哪些步骤可以选择性地自定义!
亲手试试
using System;
using Reporting;
class Program
{
public static void Main(string[] args)
{
string reportType = Console.ReadLine();
// TODO:根据 reportType 创建相应的报告生成器
// 如果 reportType 是 "sales",就创建一个 SalesReport
// 如果 reportType 是 "inventory",就创建一个 InventoryReport
// 然后调用报告的 Generate() 方法
}
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: C# 在线编译器