Menu
CoddyTech

状态模式

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

状态模式允许对象在内部状态改变时改变行为,让对象看起来像是改变了自己的类。你不必使用复杂的条件语句来处理不同的状态,而是将每种状态封装在各自的类中,并将行为委托给当前的状态对象。

该模式由一个维护当前状态引用的上下文和定义每种可能状态行为的状态类组成。当上下文的状态发生变化时,它的行为也会自动改变:

abstract class DocumentState {
  void publish(Document doc);
  String getStatus();
}

class DraftState implements DocumentState {
  @override
  void publish(Document doc) {
    print('Moving to review...');
    doc.setState(ReviewState());
  }

  @override
  String getStatus() => 'Draft';
}

class ReviewState implements DocumentState {
  @override
  void publish(Document doc) {
    print('Document published!');
    doc.setState(PublishedState());
  }

  @override
  String getStatus() => 'Under Review';
}

class PublishedState implements DocumentState {
  @override
  void publish(Document doc) {
    print('Already published.');
  }

  @override
  String getStatus() => 'Published';
}

class Document {
  DocumentState _state = DraftState();

  void setState(DocumentState state) => _state = state;
  void publish() => _state.publish(this);
  String getStatus() => _state.getStatus();
}

void main() {
  var doc = Document();
  print(doc.getStatus());  // 草稿
  doc.publish();           // 正在进入审核...
  print(doc.getStatus());  // 审核中
  doc.publish();           // 文档已发布!
  print(doc.getStatus());  // 已发布
}

每个状态类都会以不同方式处理 publish() 操作,并能将文档转换到下一个状态。Document 类不需要使用条件语句检查当前状态,只需将操作委托给当前处于活动状态的状态对象即可。这种模式非常适合具有不同运行模式的对象,例如订单处理、媒体播放器或工作流系统。

challenge icon

挑战

简单

让我们使用状态模式来构建一个交通灯系统吧!你将创建一个交通灯,让它在不同状态之间循环切换,每个状态都会决定灯的颜色以及如何切换到下一个状态。

你将把代码分成两个文件:

  • traffic_light.dart:这个文件包含状态类和交通灯上下文。创建一个抽象类 TrafficLightState,其中有两个方法:String getColor(),用于返回当前交通灯的颜色;以及 void next(TrafficLight light),用于将交通灯切换到下一个状态。 实现三个具体的状态类:
    • RedState:返回 RED 作为颜色,并在调用 next() 时输出 Stop! Light is red.,然后切换到 GreenState
    • GreenState:返回 GREEN 作为颜色,并在调用 next() 时输出 Go! Light is green.,然后切换到 YellowState
    • YellowState:返回 YELLOW 作为颜色,并在调用 next() 时输出 Caution! Light is yellow.,然后切换到 RedState
    然后创建一个 TrafficLight 类(上下文),让它从 RedState 开始。它应该有一个 setState() 方法,用于更改当前状态;一个 getColor() 方法,用于委托当前状态返回颜色;以及一个 change() 方法,用于调用当前状态的 next()。
  • main.dart:导入交通灯文件,并演示状态模式的运行过程。创建一个 TrafficLight,并输出它的初始颜色。然后调用三次 change(),每次切换后都输出颜色。这样就能看到交通灯依次经过所有状态,最后回到起始状态。

注意,TrafficLight 类不需要使用任何条件语句来决定行为。每个状态都知道自己的颜色以及下一个状态是什么。交通灯只需委托当前处于活动状态的状态来处理即可!

预期输出:

RED
Stop! Light is red.
GREEN
Go! Light is green.
YELLOW
Caution! Light is yellow.
RED

亲手试试

import 'traffic_light.dart';

void main() {
  // TODO:创建一个 TrafficLight 实例
  
  // TODO:打印初始颜色
  
  // TODO:调用 change() 并打印颜色(共 3 次,遍历所有状态)
  // 第一次变化:RED -> GREEN
  
  // 第二次变化:GREEN -> YELLOW
  
  // 第三次变化:YELLOW -> RED
}
quiz icon自我测试

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

面向对象编程中的所有课

自己练习: Dart 在线编译器