打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
通俗易懂设计模式解析——状态模式

前言

  今天我们讲的是状态模式【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;            }elseConsole.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、状态模式的结构和实现都比较复杂,使用不当容易造成代码混乱及难理解。

总结

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

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
通俗易懂设计模式解析——中介者模式
设计模式-原型模式
设计模式23:Memento Pattern (备忘录模式)
C#设计模式(12)——享元模式(Flyweight Pattern)
通俗易懂设计模式解析——备忘录模式
WebAPi的可视化输出模式(RabbitMQ、消息补偿相关)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服