结构
模式的组成
环境类(Context): 定义客户感兴趣的接口。维护一个ConcreteState子类的实例,这个实例定义当前状态。
抽象状态类(State): 定义一个接口以封装与Context的一个特定状态相关的行为。
具体状态类(ConcreteState): 每一子类实现一个与Context的一个状态相关的行为。
本文状态模式的例子使用我们生活中的交通信号灯的例子。交通信号灯一共具有三种状态,红灯,绿灯,黄灯,在这三种状态之间相互切换。如果让我们做一个demo,得到不同的状态时的信号灯颜色,最简单的写法应该是如下
if (light=='红灯')
{
Console.WriteLine("红灯");
}else if (light=='绿灯')
{
Console.WriteLine("绿灯");
}
else
{
Console.WriteLine("黄灯");
}
这样的写法通俗易懂,但是同时也存在着很大的问题。所有的 业务逻辑都在上端被定义,如果某一天业务逻辑修改了或者新增了呢,我们就要添加新的if条件,因为逻辑的高度集成,不可避免的bug就有可能触发,这是很不友好的,所以这样的方式实不可取的。
因为这一章节介绍的是状态模式,所以我们采用此方式来进行设计,其他的方式LZ也试过,也可以,不过如果是不同的状态之间带着关联,且不同状态拥有不同行为的,推荐状态模式,废话不多话,开始Lu代码
上面我们说到状态模式的组成分为三个:
环境类(Context)
抽象状态类(State)
具体状态类(ConcreteState)
就算有每一个的解释,我们还是不能很好的理解意思,接下来我用一个通俗的方式来说明。
还是用信号灯的例子来作为参考
抽象状态类,就是信号灯抽象类,里面包含颜色的显示接口
具体状态类,就是三个颜色的信号灯,继承信号灯抽象类,重载颜色显示接口
环境类,就是信号灯,负责切换不同信号灯状态
大同小异,如果我们的对象是电梯,我们是不是也可以 用同样的道理推断出来。接下来让我们对三个组成进行编码
信号灯抽象类
public enum LightColor
{
Green = 0,
Yellow = 1,
Red = 2
}
/// <summary>
/// 灯基类
/// </summary>
public abstract class LightBase
{
public LightColor Color { get; set; }
/// <summary>
/// 展示灯状态
/// </summary>
public abstract void Show();
/// <summary>
/// 切换灯颜色
/// </summary>
public abstract void Turn();
/// <summary>
/// 切换上下文
/// </summary>
public abstract void TurnContext(LightContext context);
}
具体状态类
三种颜色的信号灯实现
public class GreenLight:LightBase
{
public override void Show()
{
Console.WriteLine("绿灯");
}
public override void Turn()
{
this.Color = LightColor.Yellow;
}
public override void TurnContext(LightContext context)
{
context.LigthBase = new YellowLight();
}
}
public class RedLight : LightBase
{
public override void Show()
{
Console.WriteLine("红灯");
}
public override void Turn()
{
this.Color = LightColor.Green;
}
public override void TurnContext(LightContext context)
{
context.LigthBase = new GreenLight();
}
}
public class YellowLight : LightBase
{
public override void Show()
{
Console.WriteLine("黄灯");
}
public override void Turn()
{
this.Color = LightColor.Red;
}
public override void TurnContext(LightContext context)
{
context.LigthBase = new RedLight();
}
}
环境类
信号灯控制
/// <summary>
/// 灯控制上下文
/// </summary>
public class LightContext
{
public LightBase LigthBase;
public LightContext(LightBase lightBase)
{
this.LigthBase = lightBase;
}
/// <summary>
/// 展示当前灯颜色
/// </summary>
public void Show()
{
this.LigthBase.Show();
}
/// <summary>
/// 切换到一下个灯
/// </summary>
public void Turn()
{
this.LigthBase.TurnContext(this);
}
}
上面的代码,其实是对原来的一个简单的修改,将逻辑从三层if中分离出来,不同颜色的类完成自己的功能,实现了业务逻辑的分离。
输出
public class StateShow
{
public static void Show()
{
LightBase greeBase = new GreenLight();
LightContext context = new LightContext(greeBase);
context.Show();
context.Turn();
context.Show();
context.Turn();
context.Show();
context.Turn();
Console.Read();
}
}
重要点解析
抽象基类中重要的一个接口
public abstract void TurnContext(LightContext context);
在具体抽象类中我们可以看到对应的实现,以YellowLight(黄灯状态举例)
public override void TurnContext(LightContext context)
{
context.LigthBase = new RedLight();
}
通过实现接口,我们将传递的上下文进行更改。这么一来大概的意思就出来了,例如我们现在是绿灯状态,类就是GreenLight,对应的行为是Show(),如果我们想要切换到下一个状态,我们只需要将环境上下文进行切换,例如我们切换到红灯状态,那我们就可以操作红灯的行为Show()。
接下去就是环境类的说明
/// <summary>
/// 灯控制上下文
/// </summary>
public class LightContext
{
public LightBase LigthBase;
public LightContext(LightBase lightBase)
{
this.LigthBase = lightBase;
}
/// <summary>
/// 展示当前灯颜色
/// </summary>
public void Show()
{
this.LigthBase.Show();
}
/// <summary>
/// 切换到一下个灯
/// </summary>
public void Turn()
{
this.LigthBase.TurnContext(this);
}
}
环境类的实现也很简单,我们定义了一个内部的成员变量(LightBase),因为LightBase是所有状态灯的基类,所以我们可以在LightContext上下文内部定义操作LigthBase的方法,也就是Show。
Turn方法的实现可能有些人一下子看不懂,这个实现还是有点意思的。当前LightBase执行TurnContext(参数),参数是他自身。
举一个红灯变绿灯的例子也就能看懂了
LightContext context=new LightContext(new RedLight());
默认是红灯,我们调用
context.Turn();
执行的其实是RedLigth 的TurnContext方法
public override void TurnContext(LightContext context)
{
context.LigthBase = new GreenLight();
}