zoukankan      html  css  js  c++  java
  • 趣谈状态模式

    全文一共1543字,预计阅读时间10分钟

    定义:

      状态模式(State),当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。
      只看这个定义的话,想必会一头雾水,其实状态模式解决的问题是:
      当控制了一个对象状态转换的表达式过于复杂时,我们可以把状态的判断逻辑转移到表示不同状态的一系列的类中。这样做可以使复杂的判断逻辑简化,同时使类的职责更加单一。

    实例:

      假设每一个程序员会对应一个经验值(empiricalValue),我们会根据这个程序员的经验值,来评定这个程序员的职称,如MT,开发助理,初级程序员,中级程序员,高级程序员,专家。那么让你来完成这个程序,你会如何设计你的代码呢?
      相信有一部分人会写出和我一样的代码:
    **
     * 程序员类.
     *
     * @author jialin.li
     * @date 2019-12-30 17:38
     */
    public class Programmer {
        private int empiricalValue;
    
        public void setEmpiricalValue(int empiricalValue) {
            this.empiricalValue = empiricalValue;
        }
    
        public void evaluate() {
            if(empiricalValue < 100){
                System.out.println("MT");
            }else if(empiricalValue < 200){
                System.out.println("开发助理");
            }else if(empiricalValue < 300){
                System.out.println("初级程序员");
            }else if(empiricalValue < 400){
                System.out.println("中级程序员");
            }else if(empiricalValue < 500){
                System.out.println("高级程序员");
            }else if(empiricalValue < 600){
                System.out.println("技术专家");
            }
        }
    }
    /**
     * 客户端.
     *
     * @author jialin.li
     * @date 2019-12-30 18:28
     */
    public class Main {
        public static void main(String[] args) {
            Programmer programmer = new Programmer();
            programmer.setEmpiricalValue(50);
            programmer.evaluate();
            programmer.setEmpiricalValue(150);
            programmer.evaluate();
            programmer.setEmpiricalValue(250);
            programmer.evaluate();
            programmer.setEmpiricalValue(350);
            programmer.evaluate();
            programmer.setEmpiricalValue(450);
            programmer.evaluate();
            programmer.setEmpiricalValue(550);
            programmer.evaluate();
        }
    }

    结果:

    MT
    开发助理
    初级程序员
    中级程序员
    高级程序员
    技术专家

    这样的代码有什么问题?

      首先,evaluate方法充斥着大量的if/else,这个时候就要警惕,因为大量的if/else往往代表了该代码不符合开闭原则,每次修改或者新增条件,都会对原来的代码产生影响。
      其次,evaluate方法比较长,在面向对象编程中,方法的设计应该是短小且功能单一的,较长的方法往往意味着该方法不符合单一职责原则,或者是需要进行抽象。
      实际上,这段代码是用面向对象语言写出的面向过程的代码。这也是软件开发中常见的误区之一,并不是使用面向对象语言,写出的代码就是面向对象代码。
    这个时候应该如何对上述代码进行优化?这就引出了我们今天要介绍的设计模式:状态模式,状态模式的结构相对简单,但是用法却十分巧妙:
     
      这里将状态模式对应到我们的实例中,对经验值的判定和处理,可以被封装成一个个ConcreteState,将他们的处理方法抽象出来,就是State,而Context则起到一个维护当前状态的作用,接下来是我们修改后的代码:

    代码:

    /**
     * 状态处理接口.
     *
     * @author jialin.li
     * @date 2019-12-30 19:23
     */
    public interface State {
        void handle(Programmer programmer);
    }
    /**
     * 程序员类.
     *
     * @author jialin.li
     * @date 2019-12-30 17:38
     */
    public class Programmer {
        /**
         * 经验值
         */
        private int empiricalValue;
        /**
         * 当前状态
         */
        private State state = new MTState();
    
    
        public void setEmpiricalValue(int empiricalValue) {
            this.empiricalValue = empiricalValue;
        }
    
        public int getEmpiricalValue() {
            return empiricalValue;
        }
    
        public void setState(State state) {
            this.state = state;
        }
    
        public void handle() {
            state.handle(this);
        }
    }
    /**
     * MT.
     *
     * @author jialin.li
     * @date 2019-12-30 19:30
     */
    public class MTState implements State {
        @Override
        public void handle(Programmer programmer) {
            int empiricalValue = programmer.getEmpiricalValue();
            if (empiricalValue < 100) {
                System.out.println("MT");
            } else {
                State juniorProgrammer = new JuniorProgrammer();
                programmer.setState(juniorProgrammer);
                juniorProgrammer.handle(programmer);
            }
        }
    }
    /**
     * 助理程序员.
     *
     * @author jialin.li
     * @date 2019-12-30 19:33
     */
    public class ProgrammerAssistant implements State{
        @Override
        public void handle(Programmer programmer) {
            int empiricalValue = programmer.getEmpiricalValue();
            if(empiricalValue < 200){
                System.out.println("开发助理");
            }else{
                JuniorProgrammer juniorProgrammer = new JuniorProgrammer();
                programmer.setState(juniorProgrammer);
                juniorProgrammer.handle(programmer);
            }
        }
    }
    /**
     * 初级程序员.
     *
     * @author jialin.li
     * @date 2019-12-30 19:31
     */
    public class JuniorProgrammer implements State {
        @Override
        public void handle(Programmer programmer) {
            int empiricalValue = programmer.getEmpiricalValue();
            if (empiricalValue < 300) {
                System.out.println("初级程序员");
            } else {
                State middleProgrammer = new MiddleProgrammer();
                programmer.setState(middleProgrammer);
                middleProgrammer.handle(programmer);
            }
        }
    }
    /**
     * 中级程序员.
     *
     * @author jialin.li
     * @date 2019-12-30 19:32
     */
    public class MiddleProgrammer implements State {
        @Override
        public void handle(Programmer programmer) {
            int empiricalValue = programmer.getEmpiricalValue();
            if (empiricalValue < 400) {
                System.out.println("中级程序员");
            } else {
                SeniorProgrammer seniorProgrammer = new SeniorProgrammer();
                programmer.setState(seniorProgrammer);
                seniorProgrammer.handle(programmer);
            }
        }
    }
    /**
     * 高级程序员.
     *
     * @author jialin.li
     * @date 2019-12-30 19:34
     */
    public class SeniorProgrammer implements State {
        @Override
        public void handle(Programmer programmer) {
            int empiricalValue = programmer.getEmpiricalValue();
            if (empiricalValue < 500) {
                System.out.println("高级程序员");
            } else {
                Professor professor = new Professor();
                programmer.setState(professor);
                professor.handle(programmer);
            }
        }
    }
    /**
     * @author jialin.li
     * @date 2019-12-30 19:35
     */
    public class Professor implements State {
        @Override
        public void handle(Programmer programmer) {
            System.out.println("技术专家");
        }
    }
    /**
     * @author jialin.li
     * @date 2019-12-30 19:35
     */
    public class Professor implements State {
        @Override
        public void handle(Programmer programmer) {
            System.out.println("技术专家");
        }
    }
    /**
     * 客户端.
     *
     * @author jialin.li
     * @date 2019-12-30 19:36
     */
    public class Main {
        public static void main(String[] args) {
            Programmer programmer = new Programmer();
            programmer.setEmpiricalValue(50);
            programmer.handle();
            programmer.setEmpiricalValue(150);
            programmer.handle();
            programmer.setEmpiricalValue(250);
            programmer.handle();
            programmer.setEmpiricalValue(350);
            programmer.handle();
            programmer.setEmpiricalValue(450);
            programmer.handle();
            programmer.setEmpiricalValue(550);
            programmer.handle();
        }
    }

    结果:

    MT
    初级程序员
    初级程序员
    中级程序员
    高级程序员
    技术专家
     
      可以看出客户端代码基本没有变化,服务端代码变得更加灵活了。
      在Tomcat中,有一个LifecycleState枚举类,用于描述组件的生命周期状态,状态变更的时候,会进行上一个状态的判断,从而确定本次状态变更是否合法,这种设计也可以用在我们的状态模式中。
     
    @Override
    public final synchronized void init() throws LifecycleException {
        if (!state.equals(LifecycleState.NEW)) {
            invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
        }
    
        try {
            setStateInternal(LifecycleState.INITIALIZING, null, false);
            initInternal();
            setStateInternal(LifecycleState.INITIALIZED, null, false);
        } catch (Throwable t) {
            handleSubClassException(t, "lifecycleBase.initFail", toString());
        }
    }
    private void invalidTransition(String type) throws LifecycleException {
        String msg = sm.getString("lifecycleBase.invalidTransition", type, toString(), state);
        throw new LifecycleException(msg);
    }
      其实万变不离其宗,在设计模式中,这个宗指的就是各种设计原则。学习设计模式的时候,要时刻联系设计原则,有一种说法是,真正精通设计模式的时候,是忘记所有的设计模式(有一种张无忌学太极剑的感觉)。

      期待您的关注、推荐、收藏,同时也期待您的纠错和批评。

  • 相关阅读:
    初中几何
    角平分线导致的三角形内外角关系
    解方程
    初中|数学题目整理
    求一次函数解析式
    整式的四则运算
    分式方程
    做辅助线的方法
    线段相等的证明思路
    python2.7安装sqlite3模块
  • 原文地址:https://www.cnblogs.com/nedulee/p/12121573.html
Copyright © 2011-2022 走看看