本文作者:小黑黑

[设计模式]行为型模式之状态模式

小黑黑 1年前 ( 2019-03-05 ) 488 抢沙发
[设计模式]行为型模式之状态模式摘要: 一、引言        我们在软件开发中,应该都遇到过这种问题,我们要根据某种类型或某种状态然后去执...

一、引言

        我们在软件开发中,应该都遇到过这种问题,我们要根据某种类型或某种状态然后去执行相应的行为,然后我们就开始写了大量的if,else,这样会导致多重条件语句,并且如果再添加一种新的状态时,需要更改之前现有的代码。状态模式正是用来解决这样的问题的,状态模式将每种状态对应的行为抽象出来成为单独的对象,这样状态的变化不再依赖于对象内部的行为。

二、动机

        在很多情况下,一个对象的行为取决于一个或多个状态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的对象,这样的对象状态是从事先定义好的一系列值中取出的。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生改变。如何在运行时根据对象的状态来透明地更改对象的行为?而不会为对象操作和状态转化之间引入紧耦合?

三、意图

        允许一个对象在其内部状态修改时改变他的行为。从而使对象看起来似乎修改了其行为。        --《设计模式》  GoF

四、结构图

123.PNG

4.1  模式的组成

        1、环境类(Context):也成上下文,定义客户端所感兴趣的接口,并保留一个具体状态类的实例。这个具体状态类的实例给出此环境角色的现有状态。

        2、抽象状态角色(State):用于封装环境对象的一个特定的状态所对应的行为。

        3、具体状态角色(ConcreteState):实现抽象状态角色的接口,每一个具体类都实现了环境类的一个状态所对应的行为。

五、状态模式的具体实现

        下面我们将以交通指示灯为例,交通指示灯一共3中灯,分别是红黄绿,对应3中状态,下面看看我们用代码怎样实现吧:

    /// <summary>
    /// 交通灯抽象类,抽象状态角色
    /// </summary>
    public abstract class BaseLight
    {

        protected LightColor lightColor { get; set; }

        /// <summary>
        /// 亮灯
        /// </summary>
        public abstract void Show();

        /// <summary>
        /// 改变交通灯的颜色
        /// </summary>
        public abstract void Turn(Context context);
    }

    /// <summary>
    /// 灯的颜色
    /// </summary>
    public enum LightColor
    {
        /// <summary>
        /// 红灯
        /// </summary>
        Red,

        /// <summary>
        /// 黄灯
        /// </summary>
        Yellow,

        /// <summary>
        /// 绿灯
        /// </summary>
        Green
    }
    
    /// <summary>
    /// 环境角色
    /// </summary>
    public class Context
    {
        /// <summary>
        /// 保存当前的交通灯
        /// </summary>
        public BaseLight CurrentLight { get; set; }

        /// <summary>
        /// 亮灯
        /// </summary>
        public void Show()
        {
            this.CurrentLight.Show();
        }

        /// <summary>
        /// 改变交通灯的颜色
        /// </summary>
        public void Turn()
        {
            this.CurrentLight.Turn(this);
        }
    }
    
    /// <summary>
    /// 红灯,相当于具体状态角色
    /// </summary>
    public class LightRed : BaseLight
    {
        public LightRed()
        {
            base.lightColor = LightColor.Red;
        }

        /// <summary>
        /// 亮红灯
        /// </summary>
        public override void Show()
        {
            Console.WriteLine("红灯停");
        }

        /// <summary>
        /// 红灯亮了之后应该是绿灯量
        /// </summary>
        /// <param name="context">环境类</param>
        public override void Turn(Context context)
        {
            context.CurrentLight = new LightGreen();
        }
    }
    
    /// <summary>
    /// 黄灯类,相当于具体状态角色
    /// </summary>
    public class LightYellow : BaseLight
    {

        public LightYellow()
        {
            base.lightColor = LightColor.Yellow;
        }

        /// <summary>
        /// 亮黄灯
        /// </summary>
        public override void Show()
        {
            Console.WriteLine("黄灯亮了,等一等");
        }

        /// <summary>
        /// 黄灯亮了之后应该是红灯亮
        /// </summary>
        public override void Turn(Context context)
        {
            context.CurrentLight = new LightRed();
        }
    }
    
    /// <summary>
    /// 绿灯类,相当于具体状态角色
    /// </summary>
    public class LightGreen : BaseLight
    {

        public LightGreen()
        {
            base.lightColor = LightColor.Green;
        }

        /// <summary>
        /// 亮绿灯
        /// </summary>
        public override void Show()
        {
            Console.WriteLine("绿灯行");
        }

        /// <summary>
        /// 绿灯亮了之后应该黄灯亮
        /// </summary>
        public override void Turn(Context context)
        {
            context.CurrentLight = new LightYellow();
        }
    }
    
    class Program
    {
        static void Main(string[] args)
        {
            //先创建一个绿灯
            BaseLight light = new LightGreen();

            //创建环境类
            Context context = new Context()
            {
                CurrentLight = light
            };

            //开始循环亮灯
            context.Show();
            context.Turn();
            context.Show();
            context.Turn();
            context.Show();
            context.Turn();
            context.Show();
            context.Turn();

            Console.Read();
        }
    }

5.1  状态模式分析

        1、状态模式描述了对象状态的变化以及对象如何在每一种状态下表现出不同的行为。

        2、状态模式的关键是引入了一个抽象类来专门表示对象的状态,这个类我们叫做抽象状态类,而对象的每一种具体状态类都继承了该类,并在不同具体状态类中表现了不同状态的行为,包括状态之间的转换。

5.2  环境类与抽象类的作用

        1、环境类实际上就是拥有状态的对象,环境类有时候可以充当状态管理器的角色,可以在环境类中对状态进行切换操作。

        2、抽象状态类可以是抽象类,也可以是接口,不同状态类就是继承这个父类的不同子类,状态类的产生是由于环境类存在多个状态,同时还满足两个条件:这种状态经常需要切换,在不同的状态下对象的行为不同。因此可以将不同对象下的行为单独提取出来封装在具体的状态类中,使得环境类对象在其内部状态改变时可以改变它的行为,对象看起来似乎修改了它的类,而实际上是由于切换到不同的具体状态类实现的。由于环境类可以设置为任一具体状态类,因此它针对抽象状态类进行编程,在程序运行时可以将任一具体状态类的对象设置到环境类中,从而使得环境类可以改变内部状态,并且改变行为。

六、状态模式的优缺点

优点:

        1、将状态判断逻辑封装在每个类里面,可以简化判断的逻辑。

        2、当有新的状态出现时,可以通过增加新的状态类来进行扩展,更容易扩展。

缺点:

        1、如果状态过多的话,会导致有非常对的状态类,加大了开销。

        2、对“开闭原则”的支持不是太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态。

分享到: 网站分享代码

发表评论

快捷回复:

评论列表 (暂无评论,488人围观)参与讨论

还没有评论,来说两句吧...