设计模式-状态模式
什么是状态模式
状态模式是一种行为型设计模式,它主要用来解决对象在不同状态下的行为问题。在状态模式中,一个对象的内部状态改变时,它的行为也会随之改变。实现状态模式的关键是将对象的不同状态抽象成独立的类,然后将这些状态类与原有对象关联起来组成一个状态机。
状态模式应用场景
当一个对象的行为取决于内部状态,并且在不同状态下会有不同的行为时,可以使用状态模式。
当大量的条件判断语句存在时,可以使用状态模式来简化代码。
当一个状态需要多处使用时,可以使用状态模式将状态抽象成类,方便复用。
当需要添加新的状态并且每个状态之间的转换逻辑互不相同时,可以使用状态模式来处理状态转换的逻辑。
案例
作为一辆车它的状态其实很简单,也就是运行、加速、减速、停车状态。在停车状态,我们可以控制它启动运行,切换至运行状态;在运行状态,自动驾驶根据行驶条件控制加速减速,切换至加速减速状态;到达目的地后,泊车切换到停车状态。
状态接口:
/// <summary>
/// 状态接口类
/// </summary>
public interface ICarState
{
/// <summary>
/// 启动
/// </summary>
void Drive(Car car);
/// <summary>
/// 停车
/// </summary>
void Stop(Car car);
/// <summary>
/// 加速
/// </summary>
/// <param name="car"></param>
void SpeedUp(Car car);
/// <summary>
/// 减速
/// </summary>
/// <param name="car"></param>
void SpeedDown(Car car);
}
然后我们依次实现这四种状态。
运行状态下可以切换到其他三种状态。
/// <summary>
/// 运行状态
/// </summary>
public class RuningState : ICarState
{
public void Drive(Car car)
{
Console.WriteLine("车辆正在自动驾驶!");
}
public void Stop(Car car)
{
Console.WriteLine("车辆已停止!");
car.CurrentCarState = Car.StopState;
}
public void SpeedUp(Car car)
{
Console.WriteLine("路况良好,开始加速行驶!");
car.CurrentCarState = Car.SpeedUpState;
}
public void SpeedDown(Car car)
{
Console.WriteLine("路况一般,开始加速行驶!");
car.CurrentCarState = Car.SpeedDownState;
}
}
停车状态下,只能切换到启动状态,不可加速减速。
/// <summary>
/// 停车状态
/// </summary>
public class StopState : ICarState
{
public void Drive(Car car)
{
Console.WriteLine($"{car.Name}已启动,开始自动驾驶!");
car.CurrentCarState = Car.RunState;
}
public void Stop(Car car)
{
Console.WriteLine("车辆已停止!");
}
public void SpeedUp(Car car)
{
Console.WriteLine("车辆已停止!");
}
public void SpeedDown(Car car)
{
Console.WriteLine("车辆已停止!");
}
}
/// <summary>
/// 加速状态
/// </summary>
public class SpeedUpState : ICarState
{
public void Drive(Car car)
{
Console.WriteLine("车辆正在自动驾驶!");
}
public void Stop(Car car)
{
Console.WriteLine("车辆已停止!");
car.CurrentCarState = Car.StopState;
}
public void SpeedUp(Car car)
{
Console.WriteLine("车辆正在加速行驶!");
}
public void SpeedDown(Car car)
{
Console.WriteLine("路况一般,减速行驶!");
car.CurrentCarState = Car.SpeedDownState;
}
}
/// <summary>
/// 减速状态
/// </summary>
public class SpeedDownState : ICarState
{
public void Drive(Car car)
{
Console.WriteLine("车辆正在自动驾驶!");
}
public void Stop(Car car)
{
Console.WriteLine("车辆已停止!");
car.CurrentCarState = Car.StopState;
}
public void SpeedUp(Car car)
{
Console.WriteLine("路况良好,加速行驶!");
car.CurrentCarState = Car.SpeedUpState;
}
public void SpeedDown(Car car)
{
Console.WriteLine("车辆正在减速行驶!");
}
}
定义完状态,下面我们就来看看实际的车类。
public class Car
{
public string Name { get; set; }
public Car()
{
this.CurrentCarState = StopState;//初始状态为停车状态
}
internal static ICarState StopState = new StopState();
internal static ICarState RunState = new RuningState();
internal static ICarState SpeedDownState = new SpeedDownState();
internal static ICarState SpeedUpState = new SpeedUpState();
public ICarState CurrentCarState { get; set; }
public void Run()
{
this.CurrentCarState.Drive(this);
}
public void Stop()
{
this.CurrentCarState.Stop(this);
}
public void SpeedUp()
{
this.CurrentCarState.SpeedUp(this);
}
public void SpeedDown()
{
this.CurrentCarState.SpeedDown(this);
}
}
Car类也比较简单,主要是预先申明并实例化了几种状态并暴露设置当前状态的属性,以及提供了状态对应的行为方法,并委托给具体的状态去执行相应的动作。
下面就是简单的场景类了。
static void Main(string[] args)
{
Car tesla = new Car() {Name = "特斯拉 Model S"};
tesla.Run();
tesla.SpeedUp();
tesla.SpeedDown();
tesla.Stop();
Console.WriteLine();
}
总结
状态模式隐藏了具体的状态变化,但行为还是由状态变化驱动的。
就状态模式而言,其实就仅仅三个角色:
State——抽象状态角色:接口或抽象类,负责定义对象的所有状态对应的行为由具体状态去实现。这里对应的是我们定义的ICarState。
ConcreteState——具体状态角色:处理当前状态的行为,决定是否可以过渡到其他状态。这里对应的是我们定义的RunState、StopState、SepeedUpState、SepeedDownState。
Context——环境角色:定义行为,状态转换。这里对应的就是我们的Car类。
优缺点:
优点:结构清晰;符合OCP和SRP;封装性好。
缺点 :在状态过多的情况下,会导致具体状态类的膨胀。