首先先看一种情形,伪代码:
if(state=="空闲") {
if(预定房间) {
预定操作;
state = "已预订";
} else if(住进房间) {
入住操作;
state = "已入住";
}
} else if("已预订") {
if (住进房间) {
入住操作;
state = "已入住";
} else if(取消预定) {
取消操作;
state = "空闲";
}
}
我们在日常生活中经常见到这样的分支流程,同样的,在程序中会更多的,但是这样的代码可读性很差,而且要理解很多的逻辑,无论是自己还是别人,在看代码的时候都会容易晕的,里面的操作再复杂一些的话,直接导致维护性大大降低。
类似这样的例子,还有:
1. 电梯的运行:维修、正常、自动关门、自动开门、向上运行、向下运行,消防状态
2. 红绿灯:红灯、绿灯、 黄灯
3. 企业或政府系统:报销单据审批状态,假条审批
4. 网上购物,订单状态:下单、已付款、已发货、送货中、已收货
如果上面的逻辑都用if else这种逻辑来判断的话,可想而知,会非常的难看
下面就来说一下,状态模式到底是什么:
核心:用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题
结构:
- Context环境类:环境类中维护一个State对象,他是定义了当前的状态。
- State抽象状态类
- ConcreteState具体状态类:每一个封装了一个状态对应的行为
下面用UML图展示一下他们的关系:
不同的状态需要对应不同的行为,下面看一个比较实际的例子,通过这个列子,我们来具体分析如何通过状态模式来实现各种情况的判断。
比如红绿灯,有下面几种状态
- 红灯
- 绿灯
- 黄灯
状态图:
这个例子并不太复杂,那么如何进行编码呢?难道还是?
if(红灯) {
} else if(黄灯) {
} else if(绿灯){
}
下面贴一下代码:
public interface State {
void handle();
}
public class GreenState implements State {
@Override
public void handle() {
System.out.println("绿灯行");
}
}
public class YellowState implements State {
@Override
public void handle() {
System.out.println("黄灯多注意");
}
}
public class RedState implements State {
@Override
public void handle() {
System.out.println("红灯停");
}
}
public class TrafficLightContext {
private State state;
public void setState(State state) {
System.out.println("修改状态......");
this.state = state;
state.handle();
}
}
public class Client {
public static void main(String[] args) {
TrafficLightContext trafficLightContext = new TrafficLightContext();
trafficLightContext.setState(new GreenState());
trafficLightContext.setState(new YellowState());
trafficLightContext.setState(new RedState());
}
}
最终打印的结果:
修改状态……
绿灯行
修改状态……
黄灯多注意
修改状态……
红灯停
但是想想这样就可以了么,现在有这个一个需求,一个汽车过来,根据信号的情况来判断到底是要走还是停,还是怎样,这样还是判断不了,所以我对代码做了一定的修改:
public interface State {
void handle(TrafficLightContext context);
}
public class GreenState implements State {
@Override
public void handle(TrafficLightContext context) {
if (context.getSignal().equals("green")) {
System.out.println("绿灯行");
} else {
context.setState(new YellowState());
context.request();
}
}
}
public class RedState implements State {
@Override
public void handle(TrafficLightContext context) {
if (context.getSignal().equals("red")) {
System.out.println("红灯停");
} else {
context.setState(new GreenState());
context.request();
}
}
}
public class YellowState implements State {
@Override
public void handle(TrafficLightContext context) {
if (context.getSignal().equals("yellow")) {
System.out.println("黄灯多注意");
} else {
context.setState(new RedState());
context.request();
}
}
}
public class TrafficLightContext {
private String signal;
public String getSignal() {
return signal;
}
public void setSignal(String signal) {
this.signal = signal;
}
public TrafficLightContext() {
this.state = new GreenState();
}
private State state;
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle(this);
}
}
public class Client {
public static void main(String[] args) {
String signal = "red";
TrafficLightContext trafficLightContext = new TrafficLightContext();
trafficLightContext.setSignal(signal);
trafficLightContext.request();
}
}
为什么要这么改呢,首先,在实际使用状态模式的时候,应该把每一个状态体内的方法判断到最小范围,也就是顶多一个if else,else是无法处理的范围,如果有需要判断的属性,应该设置到context类中,然后把接口中接收context的实例对象,这样就可以在不同的状态对象中获取到context中的参数了,这样我们在实际使用的时候,就只需要生成两个类,然后再使用context中的调用方法即可。