欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-05-04 13:07:26
前言 今天我们讲的是状态模式【State Pattern】、这个名字咋一看不好理解,但是仔细一想还是比较容易的。状态模式重点关注的是状态。状态又牵扯着什么呢?房屋的状态暂且可以分为出租、签订合同、退房。那么出租对应的是什么呢?出租状态代表可以租房。可以租房是一个行为了。所以不难理解的是状态模式关注的 ......

前言

  今天我们讲的是状态模式【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#设计模式系列目录

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

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