• 闲话状态模式



    前言

    回忆下生活中状态流转的例子

    从业多年的java 开发,对设计模式的认识还知之甚少,偶然下看过几个设计模式,单例,代理,构建者,工厂,策略,观察者,装饰器,今天我们来聊一聊状态模式;


    一、什么是状态模式

    允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类

    上述的讲法较为难以理解,通俗的讲,将对象的状态和对象本身做分离,使我们的代码设计职责更加单一,低耦合,且易于扩展;

    二、实际场景

    在这里插入图片描述
    现有个小需求,需要实现自动挡汽车挂挡的功能;话不多说开始撸代码,代码如下:

    package org.example.design.pattern.state;
    
    // 档位类
    public class Shift {
    
        private State state = State.P;
    
        // 往上推
        public void turnUp() {
            switch (state) {
                case D:
                    System.out.println("OK..切N档");
                    state = State.N;
                    break;
                case N:
                    state = State.R;
                    System.out.println("OK..切R档");
                    break;
                case R:
                    state = State.P;
                    System.out.println("OK..切P档");
                    break;
                case P:
                    System.out.println("WARN.. 推不动了");
                    break;
            }
        }
    
        // 往下推
        public void turnDown() {
            switch (state) {
                case D:
                    System.out.println("WARN.. 拉不动了");
                    break;
                case N:
                    state = State.D;
                    System.out.println("OK..切D档");
                    break;
                case R:
                    state = State.N;
                    System.out.println("OK..切N档");
                    break;
                case P:
                    state = State.R;
                    System.out.println("OK.. 切R档");
                    break;
            }
        }
    
        enum State {
            D,
            R,
            N,
            P
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58

    API 使用端代码

    public static void main(String[] args) {
            Shift shift = new Shift();
            // 向上挂挡
    		shift.turnUp();
    		// 向下拉档
    		shift.turnDown();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    代码简洁,三下五除二搞定;但是思考,现有的自动挡车辆设计只有这么几个档位,后续如果又增加档位呢? 低速挡,高速挡? 这样岂不档位代码的2 个方法都要修改?(代码的开闭原则也没有了)另外现在还只是 生活中这种简单的挂挡逻辑,若是业务系统中的复杂业务,这么多switch case,也头疼;

    思考: 代码能怎么优化呢

    1.优化

    先剥离出这段switch case 判断逻辑

    // 状态接口,向上推档方法,和向下拉退档方法
    public interface State {
    
        /**
         * 向上推档
         *
         * @param shift
         */
        void turnUp(Shift shift);
    
        /**
         * 向下拉档
         *
         * @param shift
         */
        void turnDown(Shift shift);
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    每个档位各自的推档退档逻辑,这样就将对象的状态和对象逻辑分离

    
    import org.example.design.pattern.state.Shift;
    import org.example.design.pattern.state.State;
    
    // P档
    public class P implements State {
    
        @Override
        public void turnUp(Shift shift) {
            System.out.println("WARN!! 已是P 档无法向上推");
        }
    
        @Override
        public void turnDown(Shift shift) {
            shift.setState(this);
        }
    }
    
    // N档
    public class N implements State {
    
        @Override
        public void turnUp(Shift shift) {
            shift.setState(new R());
        }
    
        @Override
        public void turnDown(Shift shift) {
            shift.setState(new D());
        }
    }
    
    // D档
    public class D implements State {
    
        @Override
        public void turnUp(Shift shift) {
            shift.setState(new N());
        }
    
        @Override
        public void turnDown(Shift shift) {
            System.out.println("WARN!! 已是D 档无法向下拉");
        }
    }
    
    // R档
    public class R implements State {
    
        @Override
        public void turnUp(Shift shift) {
            shift.setState(new P());
        }
    
        @Override
        public void turnDown(Shift shift) {
            shift.setState(new N());
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    2. 思考

    我们的档位类(shift)代码该如何设计呢?又如何去掉 那些switch case 代码呢?

    package org.example.design.pattern.state;
    
    import org.example.design.pattern.state.dw.P;
    
    public class Shift {
    
        // 默认是P挡
        private State state = new P();
    
        public void turnUp() {
            state.turnUp(this);
        }
    
        public void turnDown() {
            state.turnDown(this);
        }
    
        public State getState() {
            return state;
        }
    
        public void setState(State state) {
            this.state = state;
        }
    
    }
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    档位类里边的状态和对应状态的逻辑已经分离,后续需要添加档位或者整理,只需实现 State 接口新增修改即可;


    总结

    相当实用的设计模式,有机会定要引入代码中;

  • 相关阅读:
    【软件测试】Requests库中处理cookie的几种方式
    js--处理object的常用方法
    Selenium操控元素
    七、PL/SQL 集合
    dubbo 2.5.3 升级记录 to 2.7.10
    全面讲解GRASP原则
    聊聊日志硬扫描,阿里 Log Scan 的设计与实践
    Windows安装WinDbg调试工具
    Uniapp有奖猜歌游戏系统源码 带流量主
    Json Schema介绍 和 .net 下的实践 - 基于Lateapexearlyspeed.Json.Schema - 基础1 - type关键字和string类型
  • 原文地址:https://blog.csdn.net/qq_30391051/article/details/136346475