zoukankan      html  css  js  c++  java
  • 通俗易懂设计模式解析——状态模式

    前言

      今天我们讲的是状态模式【State Pattern】、这个名字咋一看不好理解,但是仔细一想还是比较容易的。状态模式重点关注的是状态。状态又牵扯着什么呢?房屋的状态暂且可以分为出租、签订合同、退房。那么出租对应的是什么呢?出租状态代表可以租房。可以租房是一个行为了。所以不难理解的是状态模式关注的是状态的改变与行为的变化。

    状态模式介绍

    一、来由

      在软件系统中,经常状态的改变影响着行为的变化。例如房屋状态是出租既可以租房、出售既可以买卖房、不租售意味不可操作。那么如何避免对象操作和状态转换之间出现紧耦合呢?状态模式将每种状态对应的行为抽象出来成为单独新的对象,这样状态的变化不再依赖于对象内部的行为正解决了此问题。

    二、意图

      允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。

    三、案例图

     

    四、状态模式代码示例

    我们看下案例图中主要三个部分:

    环境角色:包含保留了一个具体状态的实例、给出当前状态及调用方法。

    抽象状态:定义接口、封装一个状态相对应的行为方法。

    具体状态:实现具体状态对应的的具体对应行为。

    我们继续看这个房屋的案例,针对房屋我们整理这么一个案例,租房然后签订合同。合同半年内退房无押金。租房时间达到半年退房可得押金。我们看下代码实现吧:

    namespace State_Pattern
    {
        /// <summary>
        /// 房屋对象类
        /// </summary>
      public  class StatePattern
        {
            /// <summary>
            /// 房屋Id
            /// </summary>
            public int Id { get; set; }
            /// <summary>
            /// 房屋名称
            /// </summary>
            public string Name { get; set; }
            /// <summary>
            /// 租房时间/月
            /// </summary>
            public int Time { get; set; }
            /// <summary>
            /// 房屋状态
            /// </summary>
            public HouseState State { get; set; }
            /// <summary>
            /// 是否退押金
            /// </summary>
            public bool IsDeposit { get; set; }
        }
    
        /// <summary>
        /// 房屋出租状态枚举
        /// </summary>
        public enum HouseState 
        {
            [Description("出租")]
            Lease =1,
            [Description("签订合同")]
            Leaseed = 2,
            [Description("退房")]
            Deposit = 3, 
        }
    
        /// <summary>
        /// 环境角色
        /// </summary>
        public class Environmental
        {
            public State _state;
    
            /// <summary>
            /// 初始化房屋状态
            /// </summary>
            public Environmental()
            {
                this._state = new LeaseState();
            }
    
            public StatePattern _statePattern { get; set; }
    
            /// <summary>
            /// 获取房屋对象
            /// </summary>
            /// <param name="statePattern"></param>
            public void GetStatePattern(StatePattern statePattern,State state=null)
            {
                _statePattern = statePattern;
                if (state!=null)
                {
                    _state =  state;
                }
            }
    
            /// <summary>
            /// 更改状态方法
            /// </summary>
            /// <param name="state"></param>
            public void SetState(State state) 
            {
                _state = state;
            }
    
            public void Show() 
            {
                if (this._statePattern!=null)
                {
                    _state.Handle(this);
                }
                else
                {
                    Console.WriteLine("无可操作房屋!");
                }
            }
        }
    
        /// <summary>
        /// 抽象状态接口
        /// </summary>
        public interface  State 
        {
            void Handle(Environmental environmental);
        }
    
        /// <summary>
        /// 出租状态
        /// </summary>
        public class LeaseState : State
        {
            public void Handle(Environmental environmental)
            {
                  
                //房屋出租
                if (environmental._statePattern.State==HouseState.Lease)
                {
                    Console.WriteLine($"{environmental._statePattern.Name}房屋正在出租!");
                    Console.WriteLine("如果觉得可以的话就签订租房合同!"); 
                    environmental.SetState(new LeaseedState());
                    environmental.Show();
                }
            }
        } 
    
        /// <summary>
        /// 签订合同状态
        /// </summary>
        public class LeaseedState : State
        {
            public void Handle(Environmental environmental)
            {
                 
                
                //后期办理退房手续
                if (environmental._statePattern.State == HouseState.Lease)
                {
                    Console.WriteLine($"{environmental._statePattern.Name}签订租房合同!");
                    environmental._statePattern.State = HouseState.Leaseed;
                    environmental._statePattern.Time = 1;
                    environmental.SetState(new DepositState());
                    environmental.Show();
                }
            }
        }
    
     
    
        /// <summary>
        /// 退房有押金状态
        /// </summary>
        public class DepositState : State
        {
            public void Handle(Environmental environmental)
            {
                environmental._statePattern.IsDeposit = true;
                if (environmental._statePattern.State == HouseState.Leaseed && environmental._statePattern.Time < 6)
                {
                    Console.WriteLine($"{environmental._statePattern.Name}如果现在退房的话是不能退押金的!");
                    environmental._statePattern.IsDeposit = false;
                }
                else
                    Console.WriteLine($"{environmental._statePattern.Name}如果现在退房的话是可以退押金的!");
                Console.WriteLine("考虑是否退房!");
            }
        }
    }
    namespace State_Pattern
    {
        class Program
        {
            static void Main(string[] args)
            {
                //初始化房源信息
                List<StatePattern> statePatterns = new List<StatePattern>();
                statePatterns.Add(new StatePattern {Id=1,Name="房屋一",State=HouseState.Lease }); 
    
                Environmental environmental = new Environmental();
                //房屋一出租
                environmental.GetStatePattern(statePatterns.Where(x=>x.Id==1).FirstOrDefault());
                environmental.Show();
    
                //时间大于半年可退押金
                statePatterns[0].Time = 7;
                environmental.Show();
    
    
            }
        }
    }

      在上面的代码运行之后房屋一的状态在其对象内部发送了改变,从而行为也发送了变化。刚开始的正在出租改变成了签订合同出租之后。行为变化也从签订合同转变成了退房操作。 

    使用场景及优缺点

    一、使用场景

    1、行为随着状态改变而改变的场景。

    2、条件或分支语句的替代者。

    二、优点

    1、封装了状态及行为的转换规则。

    2、在编写钱枚举出可能的状态,确定状态的种类。

    3、方便状态的增加。只需要改变状态即可改变对象的行为。扩展性好。

    4、可以多个环境一起共享一个状态对象,减少了对象个数。

    三、缺点

    1、状态模式会增加系统类和对象的个数

    2、对开闭原则不友好。增加状态需要对那些负责状态转换的代码进行修改。否则的话无法转换到最新的状态。

    3、状态模式的结构和实现都比较复杂,使用不当容易造成代码混乱及难理解。

    总结

      状态模式到这里介绍完了,状态模式模式注重的状态在内部的改变自动改变其行为。对象看起来好像改变了它的类一样。抓住重点实现。第一个是状态的变化。第二个是状态变化引起的行为变化。第三个是在状态内部改变的。把状态的转换逻辑和状态对象放在一起。继而替换一个庞大的语句条件。


         时间抓起来说是金子,抓不住就是流水。

      C#设计模式系列目录

         欢迎大家扫描下方二维码,和我一起踏上设计模式的闯关之路吧!

      

  • 相关阅读:
    请输出in.txt文件中的2 4 6 8 9 10 12行
    shell 求总分
    快速排序小结
    串的模式匹配和KMP算法
    重定向和转发的区别
    servlet中文乱码问题
    JAXP简介
    DOM常用方法总结
    初探javascript
    现在网站主流排版方式
  • 原文地址:https://www.cnblogs.com/hulizhong/p/11662201.html
Copyright © 2011-2022 走看看