Menu
CoddyTech

模板方法模式

本课属于 Coddy Dart 学习旅程的“面向对象编程”单元。第 97 课,共 110 课。

模板方法模式在基类中定义算法的骨架,让子类重写特定步骤,而不改变整体结构。基类控制工作流程,子类则自定义各个步骤。

这种模式使用继承:抽象类定义了一个模板方法,它会依次调用一系列步骤,其中一些是抽象的(必须由子类实现),另一些则有默认实现:

abstract class DataProcessor {
  // 模板方法:定义算法结构
  void process() {
    readData();
    processData();
    saveData();
  }

  void readData();      // 抽象方法:子类必须实现
  void processData();   // 抽象方法:子类必须实现

  void saveData() {     // 默认实现
    print('Data saved to database');
  }
}

class CsvProcessor extends DataProcessor {
  @override
  void readData() => print('Reading CSV file');

  @override
  void processData() => print('Parsing CSV rows');
}

class JsonProcessor extends DataProcessor {
  @override
  void readData() => print('Reading JSON file');

  @override
  void processData() => print('Parsing JSON objects');

  @override
  void saveData() => print('Saved to cloud storage');
}

void main() {
  var csv = CsvProcessor();
  csv.process();
  // 正在读取 CSV 文件
  // 正在解析 CSV 行
  // 数据已保存到数据库

  var json = JsonProcessor();
  json.process();
  // 正在读取 JSON 文件
  // 正在解析 JSON 对象
  // 已保存到云存储
}

process() 方法是模板,它定义了操作的顺序。子类以不同的方式实现 readData() 和 processData(),还可以选择重写 saveData()。这种模式的主要优点是,所有实现都保持一致的算法结构,同时各个步骤又保留了灵活性。

challenge icon

挑战

简单

让我们使用 Template Method 模式来构建一个报告生成系统!你将创建一个框架,让不同类型的报告遵循相同的总体结构,同时各自定制数据收集、输出格式设置等特定步骤。

你将把代码组织到两个文件中:

  • report_generator.dart:此文件包含抽象基类和具体的报告实现。创建一个抽象类 ReportGenerator,并添加一个名为 generate() 的模板方法,按以下顺序定义报告生成流程:fetchData()、analyzeData()、formatReport() 和 deliver()。fetchData() 和 formatReport() 方法应为抽象方法(每种报告类型以不同方式处理这些步骤),而 analyzeData() 和 deliver() 应分别使用默认实现打印 Analyzing data... 和 Report delivered via email.。 然后创建两个具体的报告类:
    • SalesReport:它的 fetchData() 打印 Fetching sales data from database...,它的 formatReport() 打印 Formatting as bar charts and tables.
    • InventoryReport:它的 fetchData() 打印 Fetching inventory levels from warehouse...,它的 formatReport() 打印 Formatting as inventory list.,并且它会重写 deliver(),使其打印 Report sent to warehouse manager.
  • main.dart:导入报告生成器文件,演示 Template Method 模式如何在允许定制的同时,保持算法结构一致。创建一个 SalesReport 并调用它的 generate() 方法。然后打印一个空行作为分隔。再创建一个 InventoryReport,并调用它的 generate() 方法。

注意,这两种报告都遵循相同的四步流程,但会根据各自的用途定制重要步骤。InventoryReport 甚至会重写默认的交付方法,将报告发送给其他收件人!

预期输出:

Fetching sales data from database...
Analyzing data...
Formatting as bar charts and tables.
Report delivered via email.

Fetching inventory levels from warehouse...
Analyzing data...
Formatting as inventory list.
Report sent to warehouse manager.

亲手试试

import 'report_generator.dart';

void main() {
  // TODO: 创建一个 SalesReport 对象并调用它的 generate() 方法

  // TODO: 打印一个空行作为分隔

  // TODO: 创建一个 InventoryReport 对象并调用它的 generate() 方法
}
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: Dart 在线编译器