记得曾经学习State设计模式的时候,记录了学习笔记.NET下的状态(State)模式 ------行为型模式 ,而最近一段时间我借助于项目的重构时间温习了关于行为型的模式----State(状态)模式。
关于State设计模式的要点和代码结构在.NET下的状态(State)模式 ------行为型模式一文中已经有比较的清晰的说明,这里我就通过一个Demo来从另一个方面介绍关于State模式的分析。
案例Demo:这样的一个场景:有一个关于PDA设备的在押人员点名的管理系统,在点名的过程中,在押人员有不同的状态(在所,不在所,外出就医,外出探亲等),不同的在押状态在PDA上显示的方式和点名的行为完全不同。
通常的方式,你会想到可以根据Prisoner(在押人员)的CurrentStatus属性来判断用户的状态来表现不同的行为。类似于下面的代码结构:

{
//不同状态有不同的行为
switch (p.CurrentStatus)
{
case 0:
{
//在所状态
break;
}
case 1:
{
//不在所状态
break;
}
case 2:
{
//外出就医
break;
}
case 3:
{
///出外探亲
break;
}
default: { break; }
}
}
这样的设计本没什么错,通过If Else语句或者Switch语句在程序运行时候根据对象的状态来表现不同的行为。但是对象的状态和对象的行为的依赖关系就是一个紧耦合的关系,而且主逻辑承担了在押人员状态的的判断和表现行为的复杂逻辑,给模块的可维护性带来了挑战?
另外如果随着系统需求的细化,我们可能要增加在押人员的其他状态,而这些状态所表现的行为有不同,发生了这样的变化我们是不是要修改这块主逻辑呢?
因此我们引入State设计模式,通过将对象和对象的状态进行分离,把对象状态的转换以及有不同状态产生的行为交给具体的状态类去实现,这样的话就能比较好的解决上述遇到的问题。
类图如下所示:

{
private Prisoner p;
public int PrisonerState
{
get
{
return p.CurrentStatus;
}
}
private State m_Current;
public State Current
{
get { return m_Current; }
set { m_Current = value; }
}
public Context(Prisoner p)
{
this.p = p;
m_Current = new InGuardState();
}
public void Process()
{
m_Current.Process(this);
}
}
Prisoner类如下:

/// 在押人员
/// </summary>
public class Prisoner
{
private string m_Name;
/// <summary>
/// 在押人员姓名
/// </summary>
public string Name
{
get { return m_Name; }
set { m_Name = value; }
}
private bool m_Sex;
/// <summary>
/// 在押人员性别
/// </summary>
public bool Sex
{
get { return m_Sex; }
set { m_Sex = value; }
}
private int m_CurrentStatus;
/// <summary>
/// 出所状态(在所:0,不在所:1,外出就医:2,出外探亲:3...)
/// </summary>
public int CurrentStatus
{
get { return m_CurrentStatus; }
set { m_CurrentStatus = value; }
}
}
State抽象类:
{
public abstract void Process(Context p);
}
在所状态类:

{
public override void Process(Context c)
{
if (c.PrisonerState == 0)
{
Console.WriteLine("在押人员状态是在所!");
}
else
{
c.Current = new OutGuardState();//不在所
c.Process();
}
}
}
不在所状态类:

{
public override void Process(Context c)
{
if (c.PrisonerState == 1)
{
Console.WriteLine("在押人员状态是不在所!");
}
else
{
c.Current = new OutDoctorState();//外出就医
c.Process();
}
}
}
外出就医状态:

{
public override void Process(Context c)
{
if (c.PrisonerState == 2)
{
Console.WriteLine("在押人员状态是外出就医!");
}
else
{
c.Current = new OutHomeState();//外出探亲
c.Process();
}
}
}
外出探亲状态:

{
public override void Process(Context c)
{
if (c.PrisonerState == 3)
{
Console.WriteLine("在押人员状态是外出探亲!");
}
else
{
Console.WriteLine("在押人员状态错误!");
}
}
}
客户端调用:

{
Prisoner p = new Prisoner();
Context process = new Context(p);
p.CurrentStatus =2;
process.Process();
p.CurrentStatus = 3;
process.Process();
p.CurrentStatus = 0;
process.Process();
}
要点:为Prisoner的CurrrentStatus操作是在各个具体的状态中进行的,在这里可以看到需要说明一下的是:这种状态的转换在真实的环境下是有序列的。(但Demo中表现并不明显,这种需要强调一下)。
再次补充说明一下状态和策略模式的区别:
前者的行为实行方式是有条件决定的,并且应当不在客户端干预的情况下自己迁移到合适的状态,而后者的行为实行方式是有客户端选择,并且能随时替换。