C# 设计模式之状态模式

总目录


前言

状态模式在我们的现实生活中也有类似的例子,例如:在我们上网购买商品的过程中,就可以查看订单的实时状态。对于商家来说,订单的状态不同,也会允许客户有不同的动作要求,比如:订单在已经处于发货状态,此订单是不能退货的。如果订单在备货阶段,客户是可以换货或者退货的。如果我们的订单已经发货了,您就等着接收货物吧,如果货物有质量问题,可以拒签,或者顺利完成交易。


1 基础介绍

  1. 定义:允许一个对象在其内部状态改变时自动改变其行为,对象看起来就像是改变了它的类。
  2. 每个对象都有其对应的状态,而每个状态又对应一些相应的行为,如果某个对象有多个状态时,那么就会对应很多的行为。那么对这些状态的判断和根据状态完成的行为,就会导致多重条件语句,并且如果添加一种新的状态时,需要更改之前现有的代码。这样的设计显然违背了开闭原则。状态模式正是用来解决这样的问题的。状态模式将每种状态对应的行为抽象出来成为单独新的对象,这样状态的变化不再依赖于对象内部的行为。
  3. 状态模式有以下角色:
    • 环境角色(Context):也称上下文,定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。
    • 抽象状态角色(State):定义一个接口,用以封装环境对象的一个特定的状态所对应的行为。
    • 具体状态角色(ConcreteState):每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。

在状态模式结构中需要理解环境类与抽象状态类的作用:

  • 环境类实际上就是拥有状态的对象,环境类有时候可以充当状态管理器(State Manager)的角色,可以在环境类中对状态进行切换操作。
  • 抽象状态类可以是抽象类,也可以是接口,不同状态类就是继承这个父类的不同子类,状态类的产生是由于环境类存在多个状态,同时还满足两个条件:这些状态经常需要切换,在不同的状态下对象的行为不同。因此可以将不同对象下的行为单独提取出来封装在具体的状态类中,使得环境类对象在其内部状态改变时可以改变它的行为,对象看起来似乎修改了它的类,而实际上是由于切换到不同的具体状态类实现的。由于环境类可以设置为任一具体状态类,因此它针对抽象状态类进行编程,在程序运行时可以将任一具体状态类的对象设置到环境类中,从而使得环境类可以改变内部状态,并且改变行为。

2 使用场景

  • 对象的行为依赖于它的状态(属性)并且可以根据它的状态改变而改变它的相关行为。

  • 代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,使客户类与类库之间的耦合增强。在这些条件语句中包含了对象的行为,而且这些条件对应于对象的各种状态

3 实现方式

在这里以酒店房间预定为案例说明:
在这里插入图片描述
状态变迁:

然后是3个状态类,这个三个状态分别对应:空闲、预订、入住。其中空闲可以完成预订和入住两个动作,预订可以完成入住和退订两个动作,入住可以退房。

状态接口

public interface IState
    {
        /// <summary>
        /// 预定房间
        /// </summary>
        void bookRoom();

        /// <summary>
        /// 退订房间
        /// </summary>
        void UnSubscribeRoom();

        /// <summary>
        /// 入住
        /// </summary>
        void CheckInRoom();

        /// <summary>
        /// 退房
        /// </summary>
        void CheckOutRoom();

    }

房间类(包含状态的环境角色)

	public class Room
    {
        /// <summary>
        /// 房间的当前状态
        /// </summary>
        private IState _state;

        public IState State
        {
            get { return _state; }
            set { _state = value; }
        }
        /// <summary>
        /// 房间的三个状态
        /// </summary>
        private IState _freeTimeState; //空闲状态

        private IState _checkInState;  //入住状态

        private IState _bookedState;   //预定状态

        /// <summary>
        /// 空闲状态
        /// </summary>
        public IState FreeTimeState
        {
            get { return _freeTimeState; }
            set { _freeTimeState = value; }
        }

        /// <summary>
        /// 入住状态
        /// </summary>
        public IState CheckInState
        {
            get { return _checkInState; }
            set { _checkInState = value; }
        }

        /// <summary>
        /// 预定状态
        /// </summary>
        public IState BookedState
        {
            get { return _bookedState; }
            set { _bookedState = value; }
        }



        public Room()
        {
            this._freeTimeState = new FreeTimeState(this);
            this._checkInState = new CheckInState(this);
            this._bookedState = new BookedState(this);
            this._state = this._freeTimeState;
        }

        /// <summary>
        /// 预定房间
        /// </summary>
        public void bookRoom()
        {
            this._state.bookRoom();
        }

        /// <summary>
        /// 退订房间
        /// </summary>
        public void UnSubscribeRoom()
        {
            this._state.UnSubscribeRoom();
        }

        /// <summary>
        /// 入住
        /// </summary>
        public void CheckInRoom()
        {
            this._state.CheckInRoom();
        }

        /// <summary>
        /// 退房
        /// </summary>
        public void CheckOutRoom()
        {
            this._state.CheckOutRoom();
        }

        public string getRoomState()
        {
            return "该房间的状态是:" + this.State.GetType().ToString();
        }


    }

空闲状态

	public class FreeTimeState:IState
    {
        private Room _room;
        public FreeTimeState()
        { }

        public FreeTimeState(Room room)
        {
            this._room= room;
        }
        public void bookRoom()
        {
            //设置状态为已经预定状态
            this._room.State = this._room.BookedState;
            Console.WriteLine("您已经成功预定了...");
        }

        public void UnSubscribeRoom()
        {
            //暂不操作
        }

        public void CheckInRoom()
        {
            this._room.State = this._room.CheckInState;
            Console.WriteLine("您已经成功入住...");
        }

        public void CheckOutRoom()
        {
            //暂不操作
        }
    }

预定状态

	public class BookedState:IState
    {
        private Room _room;
        public BookedState()
        { }

        public BookedState(Room room)
        {
            this._room= room;
        }
        public void bookRoom()
        {
            Console.WriteLine("该房间已经预定了...");
        }

        public void UnSubscribeRoom()
        {
            this._room.State = this._room.FreeTimeState;
            Console.WriteLine("退订成功,欢迎下次光临...。");
        }

        public void CheckInRoom()
        {
            this._room.State = this._room.CheckInState;
            Console.WriteLine("入住成功...");
        }

        public void CheckOutRoom()
        {
            //暂不操作
        }
    }

入住状态

	public class CheckInState:IState
    {
        private Room _room;
        public CheckInState()
        { }

        public CheckInState(Room room)
        {
            this._room= room;
        }
        public void bookRoom()
        {
            Console.WriteLine("该房间已经入住...");
        }

        public void UnSubscribeRoom()
        {
            //暂不操作
        }

        public void CheckInRoom()
        {
            Console.WriteLine("该房间已经入住...");
        }

        public void CheckOutRoom()
        {
            this._room.State = this._room.FreeTimeState;
            Console.WriteLine("退房成功...");
        }
    }

客户端调用:

		static void Main(string[] args)
        {
            //创建俩间房子
            Room[] rooms = new Room[2];
            //初始化
            for (int i = 0; i < rooms.Length; i++)
            {
                rooms[i] = new Room();
            }

            //第一间房子
            rooms[0].bookRoom(); //预定
            rooms[0].CheckInRoom();//入住
            rooms[0].bookRoom(); //再次预定
            Console.WriteLine(rooms[0].State);
            Console.WriteLine("-------------------");

            //第二间房子
            rooms[1].CheckInRoom(); //入住
            rooms[1].bookRoom(); //预定
            rooms[1].CheckInRoom(); //入住
            rooms[1].bookRoom();//再次预定
            Console.WriteLine(rooms[1].State);
            Console.WriteLine("-------------------");

            Console.Read();
        }

4 优缺点分析

优点:

  • 将状态判断逻辑每个状态类里面,可以简化判断的逻辑。
  • 当有新的状态出现时,可以通过添加新的状态类来进行扩展,扩展性好。

缺点:

  • 如果状态过多的话,会导致有非常多的状态类,加大了开销。
  • 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。

结语

希望以上内容可以帮助到大家,如文中有不对之处,还请批评指正。


参考资料:
C#设计模式之十八状态模式(State Pattern)【行为型】
C#设计模式(19)——状态者模式(State Pattern)
使用 C# 实现23种常见的设计模式
C#设计模式–状态模式

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值