Menu
CoddyTech

工厂模式

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

工厂模式将对象的创建交给单独的方法或类,让你无需指定对象的确切类即可创建对象。这与之前学过的工厂构造函数不同。工厂模式是一种设计方法,它将创建逻辑集中起来,并可根据输入返回不同类型。

考虑这样一种情况:你需要创建不同类型的通知。由工厂来决定实例化哪个类,而不是由客户端决定:

abstract class Notification {
  void send(String message);
}

class EmailNotification implements Notification {
  @override
  void send(String message) => print('Email: $message');
}

class SMSNotification implements Notification {
  @override
  void send(String message) => print('SMS: $message');
}

class NotificationFactory {
  static Notification create(String type) {
    switch (type) {
      case 'email':
        return EmailNotification();
      case 'sms':
        return SMSNotification();
      default:
        return EmailNotification();
    }
  }
}

void main() {
  var notification = NotificationFactory.create('sms');
  notification.send('Hello!');  // SMS: Hello!
}

客户端代码不需要了解 EmailNotification 或 SMSNotification,它只需向工厂请求特定类型的通知。这样一来,添加新的通知类型就很容易:你只需修改工厂,而不必修改每个创建通知的地方。

当对象的创建涉及复杂逻辑、你想对客户端隐藏实现类,或要创建的确切类型取决于运行时条件时,使用工厂模式。

challenge icon

挑战

简单

让我们使用工厂模式来构建一个文档生成器!你将创建一个系统,通过集中式工厂生成不同类型的文档(报告、发票和信件),这样客户端代码就不需要了解具体的文档类。

你将把代码整理到两个文件中:

  • document_factory.dart:在这里创建文档系统:
    • 创建一个抽象类 Document,其中包含一个方法 generate(String content),该方法返回一个 String
    • 创建三个实现 Document 的具体类:
      • Report:它的 generate 方法返回 === REPORT ===\n[content]\n=============
      • Invoice:它的 generate 方法返回 INVOICE\n--------\n[content]\nTotal Due
      • Letter:它的 generate 方法返回 Dear Reader,\n[content]\nSincerely
    • 创建一个 DocumentFactory 类,其中包含一个静态方法 create(String type),根据类型字符串返回相应的 Document:"report"、"invoice" 或 "letter"。对于任何未知类型,默认返回一个 Letter
  • main.dart:导入文档工厂,并演示工厂如何创建不同类型的文档,而客户端不需要了解具体类:
    • 使用工厂创建一份报告,并打印使用内容 Sales increased by 25% 生成的结果
    • 打印一个空行
    • 使用工厂创建一张发票,并打印使用内容 Widget x3 - $150 生成的结果
    • 打印一个空行
    • 使用工厂创建一封信,并打印使用内容 Thank you for your order 生成的结果

注意,主文件只与工厂和抽象的 Document 类型交互,它从不直接创建 Report、Invoice 或 Letter 对象!

预期输出:

=== REPORT ===
Sales increased by 25%
=============

INVOICE
--------
Widget x3 - $150
Total Due

Dear Reader,
Thank you for your order
Sincerely

亲手试试

import 'document_factory.dart';

void main() {
  // TODO: 使用 DocumentFactory.create() 创建一份报告
  // 然后打印用内容 "Sales increased by 25%" 生成的结果
  
  // TODO: 打印一个空行
  
  // TODO: 使用 DocumentFactory.create() 创建一张发票
  // 然后打印用内容 "Widget x3 - \$150" 生成的结果
  
  // TODO: 打印一个空行
  
  // TODO: 使用 DocumentFactory.create() 创建一封信
  // 然后打印用内容 "Thank you for your order" 生成的结果
}
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: Dart 在线编译器