资讯专栏INFORMATION COLUMN

设计模式之状态模式

zhangke3016 / 1312人阅读

摘要:为了实现这个正义偷笑又合理的诉求,你得先学会今天要介绍的设计模式,因为你们公司的这个流程可能就是用今天这个模式设计的。状态模式对开闭原则的支持并不太好,新增状态时,不仅得增加状态类,还得修改原来已经有的状态,让之前的状态切换到新增的状态。

一、定义

你是否经常请()假()?是不是对公司万恶的请假申请流程深痛绝。有没有想过偷偷改造这个万恶的系统,从 申请->项目经理审批->部门审批->老板审批->完成  偷偷改为  申请->完成。为了实现这个正义[偷笑]又合理的诉求,你得先学会今天要介绍的设计模式,因为你们公司的这个流程可能就是用今天这个模式设计的。来看看这个设计模式是怎么来抽象这类流程性的业务的。

状态模式【百度百科】:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。

这个定义看起来莫名其妙,咋一看,我也不知道它要表达什么。个人的理解:某个对象是有状态的,比如我们上面的请假流程,它处于项目经理状态,那项目经理可以审核你的请假申请,到了老板处理环节,老板直接把你申请单删了【哈哈】。在这不同的状态是可以有不同的操作的。

不知道你看懂了定义了没??什么?没看懂,那就直接看下面的代码咯,talk is cheap show me the code。

二、UML图

UML图如下,我直接把请假这个例子画了个UML图,如下,有一个公共的State抽象类,里面定义了两个变量来保存当前状态的状态Code,状态Name,下面为具体的状态,分别为:AppState(申请状态),ProjectManagesState(项目经理审核状态),BossState(老板审核状态),通过Context来提供给客户端使用。


三、请假流程实现

具体代码实现如下:

1、状态抽象类

package com.design.state;

public abstract class State {

    private String stateCode;
    private String stateName;
    //往下个环节走
    public abstract void toNextState(Context context);

    public State(String stateCode, String stateName){
        this.stateCode = stateCode;
        this.stateName = stateName;
    }

    public String getStateCode() {
        return stateCode;
    }

    public void setStateCode(String stateCode) {
        this.stateCode = stateCode;
    }

    public String getStateName() {
        return stateName;
    }

    public void setStateName(String stateName) {
        this.stateName = stateName;
    }
}

2、定义具体的状态

package com.design.state;

/**
 * 申请状态
 */
public class AppState extends State{

    public AppState(){
        super("Apply", "申请环节");
    }

    @Override
    public void toNextState(Context context) {
        //申请状态,这里可以做该状态下的操作
        System.out.println("我是申请人,我申请休假,下一个环节是项目经理审核!!");
        //直接进去项目经理审核状态
        context.setCurrentState(new ProjectManagesState());
    }
}


package com.design.state;

/**
 * 项目经理审核状态
 */
public class ProjectManagesState extends State{

    public ProjectManagesState(){
        super("ProjectManages", "项目经理审核环节");
    }
    @Override
    public void toNextState(Context context) {
        //项目经理审核状态,这里可以做该状态下的操做        
        System.out.println("我是项目经理,那臭小子一定有跑去面试了,哎,帮他一把,同意了,下个环节让老板审去");
        //直接进去老板审核状态
        context.setCurrentState(new BossState());
    }
}


package com.design.state;

/**
 * 老板审核状态
 */
public class BossState extends State{

    public BossState(){
        super("Boss Audit", "老板审核环节");
    }

    @Override
    public void toNextState(Context context) {
        //项目经理审核状态,这里可以做该状态下的操做
        System.out.println("我是老板,我同意你请假了!!!流程结束!");
    }

}

3、上下文类

package com.design.state;

public class Context {

    private State currentState;

    public Context(State state){
        currentState = state;
    }

    public void toNextState(){
        currentState.toNextState(this);
    };

    public State getCurrentState() {
        return currentState;
    }

    public void setCurrentState(State currentState) {
        this.currentState = currentState;
    }
}

4、写好了,看下怎么调用

package com.design.state;

public class TestMain {

    public static void main(String[] args) {
        //创建申请休假单
        Context context = new Context(new AppState());
        System.out.println("状态:"+context.getCurrentState().getStateName());
        //提交申请
        context.toNextState();
        System.out.println("状态:"+context.getCurrentState().getStateName());
        //项目经理审核
        context.toNextState();
        System.out.println("状态:"+context.getCurrentState().getStateName());
        //老板审核
        context.toNextState();
    }
}

5、执行结果


五、优缺点 1、优点

(1)、将与特定状态相关的行为局部化,将不同状态的行为分割开来。

(2)、把状态转移逻辑分布到具体状态类中,减少相互间的依赖。

看不懂这两个优点??OK,我们来解释下,先来看看,不用状态模式,我们代码会怎么写?

package com.design.state;

public class StateChange {
    private int state = 0;

    private final static int APPLY=0; //申请状态
    private final static int PROJECTMANAGES=1;//项目经理审核状态
    private final static int BOSS=2;//老板审核状态
    private final static int FINISH=3;//流程结束状态

    public void toNextState(){
       switch (state){
           case 0:
               //申请状态,做点操作
               System.out.println("写申请书!!!");
               //进入项目经理审核状态
               state = PROJECTMANAGES;
               break;
           case 1:
               System.out.println("项目经理审核,同意你申请了");
               //进入老板审核状态
               state = BOSS;
               break;
           case 2:
               System.out.println("我是老板,同意你申请了");
               //进入结束状态
               state = FINISH;
               break;
           default:
               break;
       }
    }

}

你是不是写的跟我一样呢??有没有注意到,所有的操作,无论是哪个状态的操作都是在这个类中完成的,而使用状态模式,不同状态下的行为是定义在不同的状态类下的。这就是前面说的优点1。

我们状态切换是通过switch来判断状态,再决定下一个状态的,而在状态模式下,切换到下一个状态,是在具体的状态类下进行的,可以减少if之类的判断逻辑。这就是优点2。

2、缺点

(1)、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。 

(2)、状态模式对"开闭原则"的支持并不太好,新增状态时,不仅得增加状态类,还得修改原来已经有的状态,让之前的状态切换到新增的状态。

六、总结说明

状态模式将原来通过判断实现的状态切换分散到各具体状态类中,比如上面切换到“老板审核状态”,是在“项目经理审核状态”中进行的,当状态比较多的情况,不容易理清各状态切换关系。同时它有将各状态的操作独立到状态类中,方便测试,还有分隔开各不同操作,便于阅读代码。实际运用中可根据自己的场景进行权衡。


文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/7849.html

相关文章

  • 设计模式手册状态模式

    摘要:什么是状态模式状态模式对象行为是基于状态来改变的。原文地址设计模式手册之状态模式优缺点优点封装了转化规则,对于大量分支语句,可以考虑使用状态类进一步封装。 1. 什么是状态模式? 状态模式:对象行为是基于状态来改变的。 内部的状态转化,导致了行为表现形式不同。所以,用户在外面看起来,好像是修改了行为。 Webpack4系列教程(17篇) + 设计模式手册(16篇):GitHub地址 博...

    call_me_R 评论0 收藏0
  • 设计模式手册状态模式

    摘要:什么是状态模式状态模式对象行为是基于状态来改变的。原文地址设计模式手册之状态模式优缺点优点封装了转化规则,对于大量分支语句,可以考虑使用状态类进一步封装。 1. 什么是状态模式? 状态模式:对象行为是基于状态来改变的。 内部的状态转化,导致了行为表现形式不同。所以,用户在外面看起来,好像是修改了行为。 Webpack4系列教程(17篇) + 设计模式手册(16篇):GitHub地址 博...

    Faremax 评论0 收藏0
  • 设计模式享元模式

    摘要:而享元模式的核心就是运用共享技术来有效支持大量细粒度的对象。享元模式要求将对象的属性划分为内部状态和外部状态,所以在了解享元模式之前我们先要了解两个概念内部状态外部状态。一般情况下在这四种情况下应该考虑使用享元模式。 享元模式(flyweight)是一种用于性能优化的模式,之所以用fly其意为蝇量级。而享元模式的核心就是运用共享技术来有效支持大量细粒度的对象。虽然面向对象可以非常方便的...

    Jioby 评论0 收藏0
  • 设计模式享元模式

    摘要:类图相关的设计模式享元模式和代理模式当代理模式消耗性能比较大的时候,就可以用享元模式享元模式和单例模式容器单例,享元模式就是复用对象的思想。源码中的享元模式源码地址享元模式参考慕课网设计模式精讲设计模式读书笔记享元模式 0x01.定义与类型 定义:提供了减少对象数量从而改善应用所需的对象结构的方法,系统使用少量对象,而且这些都比较相似,状态变化小,可以实现对象的多次复用。 运用共享技...

    vvpale 评论0 收藏0

发表评论

0条评论

zhangke3016

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<