状态模式(State)

结构

img_f4ab40273c179f20401c47bbbdad78fd.png
UML.png

模式的组成
环境类(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();
        }
    }
img_0f52dd3a727fc25cd078b33b16958ee1.png
show.png

重要点解析

抽象基类中重要的一个接口
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();
}

img_cd370d83a7ce97b74e58fe31d4fdadfc.png
解析.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值