趣谈状态模式

全文一共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);
}

  其实万变不离其宗,在设计模式中,这个宗指的就是各种设计原则。学习设计模式的时候,要时刻联系设计原则,有一种说法是,真正精通设计模式的时候,是忘记所有的设计模式(有一种张无忌学太极剑的感觉)。

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

原文地址:https://www.cnblogs.com/nedulee/p/12121573.html

时间: 2024-08-07 18:21:15

趣谈状态模式的相关文章

趣谈 32 种设计模式

32种设计模式趣谈 好东西不得不转 在网上看见了这篇文章,作者以轻松的语言比喻了java的32种模式,有很好的启发作用. 创建型模式 1.FACTORY-追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯德基,只管向服务员说"来四个鸡翅"就行了.麦当劳和肯德基就是生产鸡翅的Factory 工厂模式:客户类和工厂类分开.消费者任何时候需要某种产品,只需向工厂请求即可.消费者无须修改就可以接纳新产品.缺点是当产品修改时,工厂类也

自考感悟,话谈备忘录模式

引言:     2014年4月20号上午11:30,正式结束了自己的自学考试!考完之后瞬间感觉放松了开来!全身无力则是自己20号下午的唯一感受.放松了半天,今天回归正轨!又回到了和生活息息相关的设计模式上来!今天就用备忘录模式来记录一下自己这次的自考感受吧!     考试有喜有忧,对于数据库来讲,因为考试了一遍,这次又一次回到考场上,产生出了不一样的快感吧!最起码态度有了转变,解题方式上也有了提高:昨天上午考的管理经济学也许是自己这次感觉最顺利的一科!也许是有计算题的原因吧!相比之下,信息资源管

趣谈并发2:认识并发编程的利与弊

读完本文你将了解: 多线程的优点 1提高资源利用率 2响应更快 多线程的缺点 1增加资源消耗 2上下文切换的开销 3设计编码测试的复杂度增加 Java 内存模型与 CPU 内存简介 Java 中的堆 Java 中的栈 计算机中的内存寄存器缓存 多线程可能出现的问题 竞态条件与临界区 内存可见性 总结 Thanks 从上篇文章 趣谈并发(1):全面认识 Thread 我们了解了 Java 中线程的基本概念和关键方法. 在开始使用线程之前,我觉得我们有必要先了解下多线程给我们带来的好处与可能造成的损

浅谈工厂模式

一个简单的计算器例子来描述工厂模式 Operator公共接口 package com.iss.factory; public interface Operator { public int getResult(int x, int y); } Add.java package com.iss.factory; public class Add implements Operator{ @Override public int getResult(int x, int y) { // TODO A

ASP.NET应用程序生命周期趣谈(三) HttpModule

在之前的文章中,我们提到过P_Module(HttpModule)这个能干的程序员哥们儿,它通过在项目经理HttpApplication那里得到的授权,插手整个应用程序级别的事件处理.所有的HttpModule都要实现IHttpModule接口,那么我们看IHttpModule的定义: namespace System.Web { public interface IHttpModule { void Dispose(); void Init(HttpApplication context);

程序设计模式 —— State 状态模式

我应该如何阅读? 本文将使用优雅的文字风格来告诉你什么是状态模式. 注意: 1.在阅读本文之前请保证你已经掌控了 面对对象的思想与 多态的基本概念,否则将难以理解. 2.本文实现将用C++实现,你不一定必须学会C++,这些代码都有非常丰富的注释和简单的语法. 3.请不要跳着看,除非你已经学会. 那么现在开始吧 或许你会以为是类的各种状态,其实差不多.但是还有各种行为 允许一个对象在其内部状态改变时改变它的行为.实例化的对象看起来似乎修改了它的类 首先,状态,顾名思义你应该就差不多明白.它可以表示

javascript设计模式学习之十六——状态模式

状态模式的关键是区分事务内部和外部的状态,事务内部状态改变往往会带来事务的行为改变. 状态模式中有意思的一点是,一般我们谈到封装,都是优先封装对象的行为,而非对象的状态.但在状态模式中刚好相反,状态模式的关键是把事务的每种状态都封装为单独的类,跟此种状态有关的行为都封装在这个类的内部.与此同时,我们还可以把状态的切换规则实现分布在状态类中,这样就有效消除了原本存在的大量条件分支语句.

&amp;lt;十二&amp;gt;读&amp;lt;&amp;lt;大话设计模式&amp;gt;&amp;gt;之状态模式

对于状态模式,<<大话设计模式>>是以人从上班到下班到加班的状态来展开讲述的.状态模式事实上就是某一个对象在某个过程或者时间的一个状态记录,可是这个状态的顺序不能发生变化.在程序设计方面可能要比其它模式略微复杂点,请待我慢慢将来. 本人喜欢用代码来形象的讲述原理,可能是由于对单纯的看些理论的书有些反感或者无趣吧.我希望以后的教育也如此,要不大家都不高考了. . .嘿嘿说多了 状态模式:当一个对象的内在状态改变时同意改变其行为.这个对象看起来像是改变了其类. 还是代码呈现吧.概念太抽

&lt;十二&gt;读&lt;&lt;大话设计模式&gt;&gt;之状态模式

对于状态模式,<<大话设计模式>>是以人从上班到下班到加班的状态来展开讲述的.状态模式其实就是某一个对象在某个过程或者时间的一个状态记录,但是这个状态的顺序不能发生变化,在程序设计方面可能要比其他模式稍微复杂点,请待我慢慢将来. 本人喜欢用代码来形象的讲述原理,可能是因为对单纯的看些理论的书有些反感或者无趣吧,我希望以后的教育也如此,要不大家都不高考了...嘿嘿说多了 状态模式:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 还是代码呈现吧,概念太抽象了.