状态模式(State)

结构

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();
        }
    }
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();
}

解析.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 【学习难度:★★★☆☆,使用频率:★★★☆☆】直接出处:状态模式梳理和学习:https://github.com/...
    BruceOuyang阅读 4,941评论 0 2
  • 目录 本文的结构如下: 引言 什么是状态模式 模式的结构 典型代码 代码示例 状态模式和策略模式的区别 优点和缺点...
    w1992wishes阅读 4,123评论 0 6
  • STATE(状态) ———— 对象行为型模式 意图 允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改...
    tomas家的小拨浪鼓阅读 3,388评论 0 0
  • .概述 在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理。最直接的解决方案是将这些所有可能发生的情况全...
    泥孩儿0107阅读 2,944评论 0 0
  • 写文章的人都觉得自己独一无二奇思妙想,读文章的人都觉得只有我最特别我才这样。殊不知,人这一生,就担心那么几回事儿,...
    xhn喜欢你阅读 851评论 0 0