zoukankan      html  css  js  c++  java
  • 设计模式-状态模式(State)

    讲故事

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

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

    安排...

    Coding

    TimeWeather 时间段和天气枚举

        /// <summary>
        /// 时间段
        /// </summary>
        public enum Time
        {
            Morning,
            Noon,
            Afternoon,
            Night
        }
    
        /// <summary>
        /// 天气
        /// </summary>
        public enum Weather
        {
            /// <summary>
            /// 好天气
            /// </summary>
            Good,
    
            /// <summary>
            /// 坏天气
            /// </summary>
            Bad
        }
    

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

        /// <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($"
    现在是 早上,春香 服侍我起床~");
                }
                else if (Time == Time.Noon)
                {
                    Console.WriteLine($"
    现在是 中午,夏香 陪我玩耍~");
                    if (Weather == Weather.Good)
                    {
                        Console.WriteLine($"天气真好,陪我出去放风筝");
                    }
                    else
                    {
                        Console.WriteLine($"天气不好,待家给我跳舞");
                    }
                }
                else if (Time == Time.Afternoon)
                {
                    Console.WriteLine($"
    现在是 下午,秋香 服侍我用餐~");
                }
                else if (Time == Time.Night)
                {
                    Console.WriteLine($"
    现在是 晚上,冬香 服侍我就寝~");
                }
                else
                {
                    Console.WriteLine($"
    睡觉中...");
                }
            }
        }
    

    客户端 开始我一天的生活

        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("
    Happy Ending~");
                Console.ReadLine();
            }
        }
    

    结果展示:

    现在是 早上,春香 服侍我起床~
    
    现在是 中午,夏香 陪我玩耍~
    天气真好,陪我出去放风筝
    
    现在是 下午,秋香 服侍我用餐~
    
    现在是 晚上,冬香 服侍我就寝~
    

    结果还是挺美好的,但是 这个实现过程很是糟糕。

    尤其是Life.Doing()

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

    这个方法存在以下问题:

    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

  • 相关阅读:
    jquery省市联动,根据公司需求而写
    jquery.easyui使用详解,和遇到的问题,提供大家在使用的时候少走弯路(二)
    div内容滚动,无缝滚动
    使用CSS修改HTML5 input placeholder颜色( 转载 )
    如何编写规范,灵活,稳定,高质量的HTML和css代码
    div+css实现未知宽高元素垂直水平居中
    原生JavaScript实现的addclass,removeclass,hasclass,toggleclass,getbyclass
    JS判断上传图片格式是否正确
    文字超出限制字数后隐藏
    JS判断输入框值是否为空
  • 原文地址:https://www.cnblogs.com/sayook/p/12780089.html
Copyright © 2011-2022 走看看