标签:inf pool 方法 实现类 tor 工厂 优雅 inline 模式
状态模式,对象行为型模式的一种。在《设计模式 - 可复用的面向对象软件》一书中将之描述为“ 允许一个对象在其内部状态改变时改变它的行为,使对象看起来似乎修改了它的类 ”。
我们都坐过火车,火车可以简单的分为“ 开门 ”,“ 关门 ”,“ 运行 ”,“ 停止 ”四个状态。火车在这四个状态下分别可以做不同的事情。比如只有在关门时才行运行、只有在停止时才能开门。
我们在开发类似的业务时,往往会在“ 火车对象 ”中保持一个属性来标识当前的状态,并且在执行相应操作时去验证这个状态。
public class Train
{
public TrainState State { set; get; }
public void OpenDoor()
{
if(this.State == TrainState.OpenDoor)
{
Console.WriteLine("火车门已经打开");
}
else if(this.State == TrainState.CloseDoor
|| this.State == TrainState.Stop)
{
Console.WriteLine("正在打开火车门");
}
else if (this.State == TrainState.Run)
{
Console.WriteLine("火车正在运行中,不可打开火车门");
}
}
}
public enum TrainState
{
OpenDoor,
CloseDoor,
Run,
Stop
}在这种情况下,往往需要通过if-else或switch-case语句来做判断。大量if-else语句的使用使得代码的可阅读性很差,扩展起来的麻烦的很,并且使用属性来标识对象的状态也不够明确。为了避免这种情况,可使用状态模式来明确对象的状态并避免过多的使用if-else语句,让我们的代码更加优雅。
以场景中提到的火车为例,我们首先需要为火车的每个状态创建一个实现IState接口的类,以及一个上下文类Train来表示火车。如下。
public interface IState
{
Train Context { get; }
void OpenDoor();
void CloseDoor();
void Run();
void Stop();
}
public class OpenDoorState : IState
{
public Train Context { private set; get; }
public OpenDoorState(Train context)
{
this.Context = context;
}
public void OpenDoor()
{
//当前状态已经是“开门”状态,不做任何操作
}
public void CloseDoor()
{
Console.WriteLine("[OpenDoorState]:关门");
this.Context.State = TrainStateFactory.Instance.CreateCloseDoorState(this.Context);
}
public void Run()
{
throw new Exception("[OpenDoorState]:开门状态下禁止运行");
}
public void Stop()
{
//该操作只能在“运行”状态时使用,不做任何操作
}
}
public class CloseDoorState : IState
{
public Train Context { private set; get; }
public CloseDoorState(Train context)
{
this.Context = context;
}
public void OpenDoor()
{
Console.WriteLine("[CloseDoorState]:开门");
this.Context.State = TrainStateFactory.Instance.CreateOpenDoorState(this.Context);
}
public void CloseDoor()
{
//当前状态已经是“关门”状态,不做任何操作
}
public void Run()
{
Console.WriteLine("[CloseDoorState]:开车");
this.Context.State = TrainStateFactory.Instance.CreateRunState(this.Context);
}
public void Stop()
{
//该操作只能在“运行”状态时使用,不做任何操作
}
}
public class RunState : IState
{
public Train Context { private set; get; }
public RunState(Train context)
{
this.Context = context;
}
public void OpenDoor()
{
throw new Exception("[RunState]:运行状态下禁止开门");
}
public void CloseDoor()
{
//该操作只能在“开门”状态时使用,不做任何操作
}
public void Run()
{
//当前状态已经是“运行”状态,不做任何操作
}
public void Stop()
{
Console.WriteLine("[RunState]:停车");
this.Context.State = TrainStateFactory.Instance.CreateStopState(this.Context);
}
}
public class StopState : IState
{
public Train Context { private set; get; }
public StopState(Train context)
{
this.Context = context;
}
public void OpenDoor()
{
Console.WriteLine("[StopState]:开门");
this.Context.State = TrainStateFactory.Instance.CreateOpenDoorState(this.Context);
}
public void CloseDoor()
{
//该操作只能在“开门”状态时使用,不做任何操作
}
public void Run()
{
//该操作只能在“关门”状态时使用,不做任何操作
}
public void Stop()
{
//当前状态已经是“停止”状态,不做任何操作
}
}
public class Train
{
private IState _stateObj = null;
public IState State { set => this._stateObj = value; }
public void OpenDoor()
{
this._stateObj.OpenDoor();
}
public void CloseDoor()
{
this._stateObj.CloseDoor();
}
public void Run()
{
this._stateObj.Run();
}
public void Stop()
{
this._stateObj.Stop();
}
}
/// <summary>
/// 火车状态的享元工厂
/// </summary>
public class TrainStateFactory
{
//单例模式
private TrainStateFactory() { }
private static TrainStateFactory _instance = null;
private static object _sysLock = new object();
public static TrainStateFactory Instance
{
get
{
if(_instance == null)
{
lock (_sysLock)
{
if(_instance == null)
{
_instance = new TrainStateFactory();
}
}
}
return _instance;
}
}
/// <summary>
/// 状态的享元池
/// </summary>
private List<IState> StatePool { set; get; } = new List<IState>();
public IState CreateOpenDoorState(Train context)
{
var state = this.StatePool.Find(t => object.ReferenceEquals(t.Context, context) && t is OpenDoorState);
if(state == null)
{
state = new OpenDoorState(context);
this.StatePool.Add(state);
}
return state;
}
public IState CreateCloseDoorState(Train context)
{
var state = this.StatePool.Find(t => object.ReferenceEquals(t.Context, context) && t is CloseDoorState);
if (state == null)
{
state = new CloseDoorState(context);
this.StatePool.Add(state);
}
return state;
}
public IState CreateRunState(Train context)
{
var state = this.StatePool.Find(t => object.ReferenceEquals(t.Context, context) && t is RunState);
if (state == null)
{
state = new RunState(context);
this.StatePool.Add(state);
}
return state;
}
public IState CreateStopState(Train context)
{
var state = this.StatePool.Find(t => object.ReferenceEquals(t.Context, context) && t is StopState);
if (state == null)
{
state = new StopState(context);
this.StatePool.Add(state);
}
return state;
}
}示例中,定义了四个实现了IState接口的类OpenDoorState、CloseDoorState、RunState和StopState来表示火车Train的4个基本状态。同时在这些状态类中保留了Train的引用以便在执行操作后修改Train的状态(这样做的好处是可以简化Train,使其只需要关心当前要执行的操作而不必关系当前的状态,但同时也意味着IState的实现类需要保留与其本身无关的引用)。由状态类来修改Train的状态类似观察者模式(状态类发布,Train类订阅),在此基础上我们增加了一个创建火车状态的享元工厂TrainStateFactory,因为在本例中IState的实现类只存在行为而并没有内部状态,所以可以将其作为享元共享。
状态模式可以帮助我们减少条件语句if-else和switch-case的使用,将每一个条件分支(状态)封装到一个独立的类中,使得对象(封装了条件分支的类)可以不依赖其它的对象而独立的变化,并且可以很容易的增加新的状态,遵循了迪米特法则。但状态模式对开闭原则并不友好。无论如何,在增加新的状态时都需要修改那些负责转换状态的逻辑,也必然会增加系统中类和对象的个数。因为状态模式的结构与实现都较为复杂,所以增加了维护的难度。
以上,就是我对状态模式的理解,希望对你有所帮助。
示例源码:https://gitee.com/wxingChen/DesignPatternsPractice
系列汇总:https://www.cnblogs.com/wxingchen/p/10031592.html
本文著作权归本人所有,如需转载请标明本文链接(https://www.cnblogs.com/wxingchen/p/10208275.html)
二十三种设计模式[20] - 状态模式(State Pattern)
标签:inf pool 方法 实现类 tor 工厂 优雅 inline 模式
原文地址:https://www.cnblogs.com/wxingchen/p/10208275.html