状态模式
本课属于 Coddy C# 学习旅程的“面向对象编程”单元。第 60 课,共 70 课。
状态模式是一种行为型模式,它允许对象在内部状态改变时改变其行为。你可以将每种状态封装在自己的类中,并将行为委托给当前状态对象,而不是使用复杂的条件语句来处理不同的状态。
该模式由三个部分组成:定义特定状态行为的状态接口、实现该行为的具体状态类,以及保存当前状态引用的上下文类:
public interface IDocumentState
{
void Publish(Document doc);
}
public class DraftState : IDocumentState
{
public void Publish(Document doc)
{
Console.WriteLine("Moving to moderation");
doc.SetState(new ModerationState());
}
}
public class ModerationState : IDocumentState
{
public void Publish(Document doc)
{
Console.WriteLine("Publishing document");
doc.SetState(new PublishedState());
}
}
public class PublishedState : IDocumentState
{
public void Publish(Document doc)
{
Console.WriteLine("Already published");
}
}上下文保存当前状态,并将操作委托给该状态。状态对象可以通过调用上下文的 SetState() 来触发状态转换:
public class Document
{
private IDocumentState _state = new DraftState();
public void SetState(IDocumentState state) => _state = state;
public void Publish() => _state.Publish(this);
}
var doc = new Document();
doc.Publish(); // 进入审核阶段
doc.Publish(); // 正在发布文档
doc.Publish(); // 已经发布状态模式消除了用于检查当前状态的冗长 if-else 或 switch 语句。每个状态类只处理自己的行为,让代码更易于维护,也更容易扩展新状态。
挑战
简单让我们使用状态模式构建一个交通灯系统。交通灯会在不同状态(红色、黄色、绿色)之间循环,每种状态都会决定灯切换时会发生什么。你将把每种灯的状态封装在单独的类中,而不是使用复杂的条件语句。
你将把代码组织在 3 个文件中:
TrafficLightState.cs:在Traffic命名空间中定义ITrafficLightState接口,并包含一个方法Change(TrafficLight light)。然后创建 3 个具体的状态类:RedState:调用Change时,输出Red - Stop! Changing to Green...,并将灯切换到GreenStateGreenState:输出Green - Go! Changing to Yellow...,并切换到YellowStateYellowState:输出Yellow - Caution! Changing to Red...,并切换到RedState
TrafficLight.cs:在同一命名空间中创建一个TrafficLight类。它是你的上下文类,用于维护当前状态。它默认从RedState开始,并包含:- 一个
SetState(ITrafficLightState state)方法,供状态对象触发状态切换 - 一个
Change()方法,将调用委托给当前状态的Change方法
- 一个
Program.cs:创建一个TrafficLight,根据输入循环切换状态,将所有内容整合起来。
你会收到一个输入:
- 交通灯切换的次数(一个整数)
创建一个 TrafficLight(它从红灯状态开始),并按指定次数调用 Change()。
例如,如果输入是 3,输出应为:
Red - Stop! Changing to Green...
Green - Go! Changing to Yellow...
Yellow - Caution! Changing to Red...如果输入是 5,灯会循环回到起始状态:
Red - Stop! Changing to Green...
Green - Go! Changing to Yellow...
Yellow - Caution! Changing to Red...
Red - Stop! Changing to Green...
Green - Go! Changing to Yellow...注意,TrafficLight 类不包含关于每种颜色代表什么或接下来会切换到哪种颜色的逻辑,所有这些信息都保存在各个状态类中。每种状态都负责自己的行为,并触发切换到下一个状态!
亲手试试
using System;
using Traffic;
class Program
{
public static void Main(String[] args)
{
// 读取交通信号灯需要切换的次数
int n = Convert.ToInt32(Console.ReadLine());
// TODO:创建一个 TrafficLight 实例(默认从 RedState 开始)
// TODO:使用循环调用 Change() 方法 n 次
}
}
这节课包含一个小测验。开始学习即可作答,并记录你的进度。
面向对象编程中的所有课
自己练习: C# 在线编译器