设计模式-状态模式(State)

讲故事

彩虹环绕这秋香、春香、夏香,秋香、春香、夏香环绕着我,这时键盘飞入个人怀中(小朋友,你是否有许多的问号),飞速的敲击键盘,不一下子婀娜多姿的冬香也出如今个人面前。html

有了四大美人相伴,那个人生活要好好从新安排一下,早上谁来服侍我,中午谁来服侍我,下午谁来服侍我,晚上谁来服侍我,想一想都美啊~git

安排...app

Coding

TimeWeather 时间段和天气枚举this

/// <summary>
    /// 时间段
    /// </summary>
    public enum Time
    {
        Morning,
        Noon,
        Afternoon,
        Night
    }

    /// <summary>
    /// 天气
    /// </summary>
    public enum Weather
    {
        /// <summary>
        /// 好天气
        /// </summary>
        Good,

        /// <summary>
        /// 坏天气
        /// </summary>
        Bad
    }

Life类,模拟一天的生活,根据不一样时间段来判断谁来服侍我干什么code

/// <summary>
    /// 生活
    /// </summary>
    public class Life
    {
        /// <summary>
        /// 时间段
        /// </summary>
        public Time Time { get; set; }

        /// <summary>
        /// 天气
        /// </summary>
        public Weather Weather { get; set; }

        /// <summary>
        /// 干啥子
        /// </summary>
        public void Doing()
        {
            if (Time == Time.Morning)
            {
                Console.WriteLine($"\n如今是 早上,春香 服侍我起床~");
            }
            else if (Time == Time.Noon)
            {
                Console.WriteLine($"\n如今是 中午,夏香 陪我玩耍~");
                if (Weather == Weather.Good)
                {
                    Console.WriteLine($"天气真好,陪我出去放风筝");
                }
                else
                {
                    Console.WriteLine($"天气很差,待家给我跳舞");
                }
            }
            else if (Time == Time.Afternoon)
            {
                Console.WriteLine($"\n如今是 下午,秋香 服侍我用餐~");
            }
            else if (Time == Time.Night)
            {
                Console.WriteLine($"\n如今是 晚上,冬香 服侍我就寝~");
            }
            else
            {
                Console.WriteLine($"\n睡觉中...");
            }
        }
    }

客户端 开始我一天的生活htm

internal class Program
    {
        private static void Main(string[] args)
        {
            var life = new Life();
            //设置天气
            life.Weather = Weather.Good;

            life.Time = Time.Morning;
            life.Doing();

            life.Time = Time.Noon;
            life.Doing();

            life.Time = Time.Afternoon;
            life.Doing();

            life.Time = Time.Night;
            life.Doing();

            Console.WriteLine("\nHappy Ending~");
            Console.ReadLine();
        }
    }

结果展现:对象

如今是 早上,春香 服侍我起床~

如今是 中午,夏香 陪我玩耍~
天气真好,陪我出去放风筝

如今是 下午,秋香 服侍我用餐~

如今是 晚上,冬香 服侍我就寝~

结果仍是挺美好的,可是 这个实现过程非常糟糕。blog

尤为是Life.Doing()接口

/// <summary>
        /// 干啥子
        /// </summary>
        public void Doing()
        {
            if (Time == Time.Morning)
            {
                Console.WriteLine($"\n如今是 早上,春香 服侍我起床~");
            }
            else if (Time == Time.Noon)
            {
                Console.WriteLine($"\n如今是 中午,夏香 陪我玩耍~");
                if (Weather == Weather.Good)
                {
                    Console.WriteLine($"天气真好,陪我出去放风筝");
                }
                else
                {
                    Console.WriteLine($"天气很差,待家给我跳舞");
                }
            }
            else if (Time == Time.Afternoon)
            {
                Console.WriteLine($"\n如今是 下午,秋香 服侍我用餐~");
            }
            else if (Time == Time.Night)
            {
                Console.WriteLine($"\n如今是 晚上,冬香 服侍我就寝~");
            }
            else
            {
                Console.WriteLine($"\n睡觉中...");
            }
        }

这个方法存在如下问题:开发

  1. 方法很长(若是咱们再把时间段细分如下,或者每一个时间段作的事情增长。实际开发中,可能每一个判断中包含不少很复杂的业务逻辑)。开发过程当中,咱们要尽可能保持每一个方法体代码行数不超过50行。
  2. 判断分支太多。if else不少,而且还存在嵌套,该方法的责任过大,同时也不方便阅读。
  3. 维护困难。之后要增长时间段,好比我 想在深夜 有人来服侍我吃宵夜,要修改Life.Doing()来实现,这彻底违背了个人人生信条的第3条!

如何解决上面的问题呢?这时房中升起了四个金光闪闪的大字——状态模式

状态模式

敲黑板·划重点

定义: 当一个对象的内在状态改变时容许改变其行为,这个对象看起来像是改变了其类。(上面案例中,时间段Time就是Life对象的状态,当Time改变时,Life的行为Doing()就改变了)

做用: 主要解决当控制一个对象状态转换条件表达式过于复杂时的状况。把状态的判断逻辑转移到表示不一样状态的一系列类当中,能够把复杂的判断逻辑简化。

好处: 将与特定状态相关的行为局部化,而且将不一样状态的行为分割开来。

思想: 将特定状态相关的行为都放入一个对象中,因为全部与状态相关的代码都存在于具体的状态对象中,因此经过定义新的子类就能够很容易地增长新的状态和转换。消除庞大的条件分支语句,经过把各类状态转移逻辑分布到状态的子类之间,来减小相互间的依赖。

解决方法已经找到,就开始干吧...

Code Upgrade

ITimeHandle接口,定义各类时间段(状态)的行为。

public interface ITimeHandle
    {
        /// <summary>
        /// 干啥子
        /// </summary>
        /// <param name="life"></param>
        public void Doing(Life life);
    }

Life类,属性中包含ITimeHandle,行为Doing()交个具体的时间段操做(状态对象)。

/// <summary>
    /// 生活
    /// </summary>
    public class Life
    {
        private ITimeHandle _timeHandle;

        /// <summary>
        /// 时间段
        /// </summary>
        public Time Time { get; set; }

        /// <summary>
        /// 天气
        /// </summary>
        public Weather Weather { get; set; }

        /// <summary>
        /// 初始化 一天生活的 时间段
        /// </summary>
        public Life()
        {
            //默认设置时间为 上午
            _timeHandle = new MorningTime();
        }

        /// <summary>
        /// 设置时间段对应的操做类
        /// </summary>
        /// <param name="timeHandle"></param>
        public void SetTimeHandle(ITimeHandle timeHandle)
        {
            _timeHandle = timeHandle;
        }

        /// <summary>
        /// 干啥子
        /// </summary>
        public void Doing()
        {
            _timeHandle.Doing(this);
        }
    }

MorningTimeNoonTimeAfternoonTimeNightTime类实现ITimeHandle接口(这也就是 思想 中:将与特定状态相关的行为局部化。全部与状态相关的代码都存在于具体的状态对象中)。在具体的时间段类中来判断改该作什么(这也就是 做用 中:把状态的判断逻辑转移到表示不一样状态的一系列类当中,能够把复杂的判断逻辑简化)。

/// <summary>
    /// 早上 干什么
    /// </summary>
    public class MorningTime : ITimeHandle
    {
        public void Doing(Life life)
        {
            if (life.Time == Time.Morning)
            {
                Console.WriteLine($"如今是 早上,春香 服侍我起床~");
            }
            else
            {
                life.SetTimeHandle(new NoonTime());
                life.Doing();
            }
        }
    }

    /// <summary>
    /// 中午 干什么
    /// </summary>
    public class NoonTime : ITimeHandle
    {
        public void Doing(Life life)
        {
            if (life.Time == Time.Noon)
            {
                Console.WriteLine($"如今是 中午,夏香 陪我玩耍~");
                if (life.Weather == Weather.Good)
                {
                    Console.WriteLine($"天气真好,陪我出去放风筝");
                }
                else
                {
                    Console.WriteLine($"天气很差,待家给我跳舞");
                }
            }
            else
            {
                life.SetTimeHandle(new AfternoonTime());
                life.Doing();
            }
        }
    }

    /// <summary>
    /// 下午 干什么
    /// </summary>
    public class AfternoonTime : ITimeHandle
    {
        public void Doing(Life life)
        {
            if (life.Time == Time.Afternoon)
            {
                Console.WriteLine($"如今是 下午,秋香 服侍我用餐~");
            }
            else
            {
                life.SetTimeHandle(new NightTime());
                life.Doing();
            }
        }
    }

    /// <summary>
    /// 晚上 干什么
    /// </summary>
    public class NightTime : ITimeHandle
    {
        public void Doing(Life life)
        {
            if (life.Time == Time.Night)
            {
                Console.WriteLine($"如今是 晚上,冬香 服侍我就寝~");
            }
            else
            {
                Console.WriteLine($"睡觉中...");
            }
        }
    }

客户端代码 和 输出结果 同上

如今,咱们再来看看Life.Doing()

/// <summary>
    /// 干啥子
    /// </summary>
    public void Doing()
    {
        _timeHandle.Doing(this);
    }

方法简洁明了,消除了过多的判断分支。

同时Life类的职责简化了,作到代码的责任分解。符合了我人生信条的第1条和第3条。

这时候,咱们再要增长一个深夜吃夜宵的时间段,Life类就不须要动了。咱们只需增长WeeHoursTime类实现ITimeHandle,调整NightTime中的判断就能够了。

吟诗

糟糕的问题完美解决,我心甚欢,吟诗一首:

桃花坞里桃花庵,

桃花庵下桃花仙。

桃花仙人敲代码,

桃花运来年复年。

示例代码地址: https://gitee.com/sayook/DesignMode/tree/master/State

相关文章
相关标签/搜索