定义
当一个对象的内部状态改变时,允许改变其行为,这个对象看起来像是改变了其类。
状态模式主要解决的是当控制一个对象状态转换的条件过于复杂的情况。吧状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的控制逻辑转换。当然,如果这个状态逻辑很简单,就没必要用状态模式了。
状态图
State:抽象状态接口,定义一个接口以封装与Context的一个特定状态相关的行为。
ConcreteState:具体状态,每一个子类实现一个与Context状态相关的行为。
Context:状态上下文,维护一个ConcreteState的一个实例,这个实例定义当前的状态。
好处与用处
- 将特定状态相关的行为都放到一个对象中,由于所有与状态相关的代码,都存在于某个ConcreteState中,所以通过定义新的子类可以新增新的状态和转换。
- 这样做的目的就是消除庞大的条件分支语句,大的分支和判断使得他们难以修改和扩展。
- 状态模式通过把各种状态专一逻辑分部到State的实现类中,来减少相互之间的依赖。
- 当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为,就可以考虑使用状态模式。
生活常见场景
- 电梯的运行
维修、正常、自动关门、自动开门、向上运行、向下运行、消防状态、紧急状态。 - 红绿灯
红灯、黄灯、绿灯。 - 企业和政府的系统
公文或假条的审批状态。 - 网购时订单的状态
下单、已付款、已发货、送货中、已收货。 - 酒店客房的入住状态
空闲、已预订、已入住。
模拟案例
酒店客房房间状态变化
if (state == "空闲") {
if (预定房间) {
预定操作;
state = "预定";
}else if(入住房间) {
入住操作;
state = "入住";
}
} else if(state == "预定") {
if (取消预定) {
取消预定操作;
state = "空闲";
}else if(入住房间) {
入住操作;
state = "入住";
}
} else {
if (退房) {
退房操作;
state = "空闲";
}else if(续房) {
入住操作;
state = "入住";
}
}
当遇到这种频繁且大量的分支判断状态的时候,可以使用状态模式,因为这样的代码难以扩展和维护。
代码实现
- State状态接口,定义一个状态的行为
/**
* User:tumbler
* Desc:状态模式--状态接口
*/
public interface State {
void handle();
}
- 具体状态ConcreteState,实现State接口。空闲、预定、入住
/**
* User:tumbler
* Desc:状态模式--具体状态ConcreteState--空闲
*/
public class FreeState implements State {
@Override
public void handle() {
System.out.println("房间空闲!!!");
}
}
/**
* User:tumbler
* Desc:状态模式--具体状态ConcreteState--预定
*/
public class BookedState implements State {
@Override
public void handle() {
System.out.println("房间已预订!!!");
}
}
/**
* User:tumbler
* Desc:状态模式--具体状态ConcreteState--空闲
*/
public class CheckedState implements State {
@Override
public void handle() {
System.out.println("房间已入住!!!");
}
}
- 测试
/**
* User:tumbler
* Desc:状态模式--测试
*/
public class Client {
public static void main(String[] args) {
Context context = new Context();
context.setState(new FreeState());
context.setState(new CheckedState());
}
}
运行结果:
修改状态。。。
房间空闲!!!
修改状态。。。
房间已入住!!!
- UML图