你是否常常请(偷)假(懒)?是否是对公司万恶的请假申请流程深恶痛绝。有没有想过偷偷改造这个万恶的系统,从 申请->项目经理审批->部门审批->老板审批->完成 偷偷改成 申请->完成。为了实现这个正义[偷笑]又合理的诉求,你得先学会今天要介绍的设计模式,由于大家公司的这个流程可能就是用今天这个模式设计的。来看看这个设计模式是怎么来抽象这类流程性的业务的。面试
状态模式【百度百科】:当一个对象的内在状态改变时容许改变其行为,这个对象看起来像是改变了其类。设计模式
这个定义看起来莫名其妙,咋一看,我也不知道它要表达什么。我的的理解:某个对象是有状态的,好比咱们上面的请假流程,它处于项目经理状态,那项目经理能够审核你的请假申请,到了老板处理环节,老板直接把你申请单删了【 哈哈】。在这不一样的状态是能够有不一样的操做的。不知道你看懂了定义了没??什么?没看懂,那就直接看下面的代码咯,talk is cheap show me the code。
bash
UML图以下,我直接把请假这个例子画了个UML图,以下,有一个公共的State抽象类,里面定义了两个变量来保存当前状态的状态Code,状态Name,下面为具体的状态,分别为:AppState(申请状态),ProjectManagesState(项目经理审核状态),BossState(老板审核状态),经过Context来提供给客户端使用。ide
具体代码实现以下:测试
一、状态抽象类ui
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;
}
}
复制代码
二、定义具体的状态this
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("我是老板,我赞成你请假了!!!流程结束!");
}
}
复制代码
三、上下文类spa
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;
}
}
复制代码
四、写好了,看下怎么调用设计
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();
}
}复制代码
五、执行结果code
(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。
(1)、状态模式的结构与实现都较为复杂,若是使用不当将致使程序结构和代码的混乱。
(2)、状态模式对"开闭原则"的支持并不太好,新增状态时,不只得增长状态类,还得修改原来已经有的状态,让以前的状态切换到新增的状态。
状态模式将原来经过判断实现的状态切换分散到各具体状态类中,好比上面切换到“老板审核状态”,是在“项目经理审核状态”中进行的,当状态比较多的状况,不容易理清各状态切换关系。同时它有将各状态的操做独立到状态类中,方便测试,还有分隔开各不一样操做,便于阅读代码。实际运用中可根据本身的场景进行权衡。