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

    什么是状态模式

    状态模式允许一个对象在其内部状态改变的时候改变其行为。这个对象看上去就像是改变了它的类一样。

    状态模式应用场景

    1.一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。

    2.操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。 通常,有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。

     

    案例:

    作为一辆车它的状态其实很简单,也就是运行、加速、减速、停车状态。在停车状态,我们可以控制它启动运行,切换至运行状态;在运行状态,自动驾驶根据行驶条件控制加速减速,切换至加速减速状态;到达目的地后,泊车切换到停车状态。

    状态接口:
      /// <summary>
        /// 状态接口类
        /// </summary>
        public interface ICarState
        {
            /// <summary>
            /// 启动
            /// </summary>
            void Drive(Car car);
    
            /// <summary>
            /// 停车
            /// </summary>
            void Stop(Car car);
    
            /// <summary>
            /// 加速
            /// </summary>
            /// <param name="car"></param>
            void SpeedUp(Car car);
    
            /// <summary>
            /// 减速
            /// </summary>
            /// <param name="car"></param>
            void SpeedDown(Car car);
        }

     然后我们依次实现这四种状态。
    运行状态下可以切换到其他三种状态。

    /// <summary>
    /// 运行状态
    /// </summary>
    public class RuningState : ICarState
    {
        public void Drive(Car car)
        {
            Console.WriteLine("车辆正在自动驾驶!");
        }
    
        public void Stop(Car car)
        {
            Console.WriteLine("车辆已停止!");
            car.CurrentCarState = Car.StopState;
        }
    
        public void SpeedUp(Car car)
        {
            Console.WriteLine("路况良好,开始加速行驶!");
            car.CurrentCarState = Car.SpeedUpState;
        }
    
        public void SpeedDown(Car car)
        {
            Console.WriteLine("路况一般,开始加速行驶!");
            car.CurrentCarState = Car.SpeedDownState;
        }
    }

    停车状态下,只能切换到启动状态,不可加速减速。

    /// <summary>
    /// 停车状态
    /// </summary>
    public class StopState : ICarState
    {
        public void Drive(Car car)
        {
            Console.WriteLine($"{car.Name}已启动,开始自动驾驶!");
            car.CurrentCarState = Car.RunState;
        }
    
        public void Stop(Car car)
        {
            Console.WriteLine("车辆已停止!");
        }
    
        public void SpeedUp(Car car)
        {
            Console.WriteLine("车辆已停止!");
        }
    
        public void SpeedDown(Car car)
        {
            Console.WriteLine("车辆已停止!");
        }
    }
    /// <summary>
    /// 加速状态
    /// </summary>
    public class SpeedUpState : ICarState
    {
        public void Drive(Car car)
        {
            Console.WriteLine("车辆正在自动驾驶!");
        }
    
        public void Stop(Car car)
        {
            Console.WriteLine("车辆已停止!");
            car.CurrentCarState = Car.StopState;
        }
    
        public void SpeedUp(Car car)
        {
            Console.WriteLine("车辆正在加速行驶!");
        }
    
        public void SpeedDown(Car car)
        {
            Console.WriteLine("路况一般,减速行驶!");
            car.CurrentCarState = Car.SpeedDownState;
        }
    }
    /// <summary>
    /// 减速状态
    /// </summary>
    public class SpeedDownState : ICarState
    {
        public void Drive(Car car)
        {
            Console.WriteLine("车辆正在自动驾驶!");
        }
    
        public void Stop(Car car)
        {
            Console.WriteLine("车辆已停止!");
            car.CurrentCarState = Car.StopState;
        }
    
        public void SpeedUp(Car car)
        {
            Console.WriteLine("路况良好,加速行驶!");
            car.CurrentCarState = Car.SpeedUpState;
        }
    
        public void SpeedDown(Car car)
        {
            Console.WriteLine("车辆正在减速行驶!");
        }
    }

    定义完状态,下面我们就来看看实际的车类。

    public class Car
    {
        public string Name { get; set; }
    
        public Car()
        {
            this.CurrentCarState = StopState;//初始状态为停车状态
        }
    
        internal static ICarState StopState = new StopState();
        internal static ICarState RunState = new RuningState();
        internal static ICarState SpeedDownState = new SpeedDownState();
        internal static ICarState SpeedUpState = new SpeedUpState();
    
        public ICarState CurrentCarState { get; set; }
    
        public void Run()
        {
            this.CurrentCarState.Drive(this);
        }
    
        public void Stop()
        {
            this.CurrentCarState.Stop(this);
        }
    
        public void SpeedUp()
        {
            this.CurrentCarState.SpeedUp(this);
        }
        public void SpeedDown()
        {
            this.CurrentCarState.SpeedDown(this);
        }
    }

    Car类也比较简单,主要是预先申明并实例化了几种状态并暴露设置当前状态的属性,以及提供了状态对应的行为方法,并委托给具体的状态去执行相应的动作。

    下面就是简单的场景类了。

    static void Main(string[] args)
    {
        Car tesla = new Car() {Name = "特斯拉 Model S"};
        tesla.Run();
        tesla.SpeedUp();
        tesla.SpeedDown();
        tesla.Stop();
    
        Console.WriteLine();
    }

    总结:

    状态模式隐藏了具体的状态变化,但行为还是由状态变化驱动的。
    就状态模式而言,其实就仅仅三个角色:

    • State——抽象状态角色:接口或抽象类,负责定义对象的所有状态对应的行为由具体状态去实现。这里对应的是我们定义的ICarState
    • ConcreteState——具体状态角色:处理当前状态的行为,决定是否可以过渡到其他状态。这里对应的是我们定义的RunStateStopStateSepeedUpStateSepeedDownState
    • Context——环境角色:定义行为,状态转换。这里对应的就是我们的Car类。

    优缺点:

    优点:结构清晰;符合OCP和SRP;封装性好。
    缺点 :在状态过多的情况下,会导致具体状态类的膨胀。

    应用场景:

    1. 行为随状态改变而改变。
    2. 状态已确定,且状态不宜过多。
    3. 重构if..elseswitch..case的不二之选。
  • 相关阅读:
    博客园
    未释放的已删除文件
    ssh连接缓慢
    剑指 Offer 38. 字符串的排列
    剑指 Offer 37. 序列化二叉树
    剑指 Offer 50. 第一个只出现一次的字符
    剑指 Offer 36. 二叉搜索树与双向链表
    剑指 Offer 35. 复杂链表的复制
    剑指 Offer 34. 二叉树中和为某一值的路径
    剑指 Offer 33. 二叉搜索树的后序遍历序列
  • 原文地址:https://www.cnblogs.com/fanfan-90/p/12865655.html
Copyright © 2011-2022 走看看