趣谈状态模式
全文一共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方法比较长,在面向对象编程中,方法的设计应该是短小且功能单一的,较长的方法往往意味着该方法不符合单一职责原则,或者是需要进行抽象。
实际上,这段代码是用面向对象语言写出的面向过程的代码。这也是软件开发中常见的误区之一,并不是使用面向对象语言,写出的代码就是面向对象代码。
这个时候应该如何对上述代码进行优化?这就引出了我们今天要介绍的设计模式:状态模式,状态模式的结构相对简单,但是用法却十分巧妙:
![](https://img2018.cnblogs.com/i-beta/1245470/201912/1245470-20191230202930901-794428609.jpg)
这里将状态模式对应到我们的实例中,对经验值的判定和处理,可以被封装成一个个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); }
其实万变不离其宗,在设计模式中,这个宗指的就是各种设计原则。学习设计模式的时候,要时刻联系设计原则,有一种说法是,真正精通设计模式的时候,是忘记所有的设计模式(有一种张无忌学太极剑的感觉)。
期待您的关注、推荐、收藏,同时也期待您的纠错和批评。