基本定义
- 对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
模式结构
- Context(环境类): 可以包括一些内部状态。
- State(抽象状态类):所有具体状态的共同接口,任何状态都实现这个相同的接口,状态之间互相转换。
- ConcreteState(具体状态类):用于处理来自Context的请求,每一个ConcreteState都提供了它对自己请求的实现,
模式实现
- State 抽象状态类
public interface State {
//预定房间
void reservationRoom();
//退订房间
void unsubscribeRoom();
//入住
void checkinRoom();
//退房
void checkoutRoom();
}
- ConcreteState 具体状态类
空闲状态
@Slf4j
public class FreeState implements State{
Room room;
public FreeState(Room room) {
this.room = room;
}
/**
* 房间状态改变,还需修改内部状态
*/
@Override
public void reservationRoom() {
log.info("您已预定房间");
room.setState(room.reservationState);
}
@Override
public void unsubscribeRoom() {
}
@Override
public void checkinRoom() {
log.info("您已入住成功");
room.setState(room.checkinState);
}
@Override
public void checkoutRoom() {
}
}
预定状态
@Slf4j
public class ReservationState implements State{
Room room;
public ReservationState(Room room) {
this.room = room;
}
@Override
public void reservationRoom() {
log.error("预定失败,该房间已经被预定");
}
@Override
public void unsubscribeRoom() {
log.info("您已经取消预定");
room.setState(room.freeState);
}
@Override
public void checkinRoom() {
log.info("您已入住成功");
room.setState(room.checkinState);
}
@Override
public void checkoutRoom() {
}
}
入住状态
@Slf4j
public class CheckinState implements State{
Room room;
public CheckinState(Room room) {
this.room = room;
}
@Override
public void reservationRoom() {
log.error("预定失败,该房间已经入住");
}
@Override
public void unsubscribeRoom() {
}
@Override
public void checkinRoom() {
log.error("入住失败,该房间已经入住");
}
@Override
public void checkoutRoom() {
log.info("您已退房");
room.setState(room.freeState);
}
}
- Context 环境类
/**
* 状态模式特点一、除了关联抽象状态,还需要关联我们具体状态。
* 状态模式特点二, 提供所有的抽象与具体的状态类。并且在无参构造方法初始化状态类。
* 还需要提供所有属性的set方法,供状态类使用,需要提供调用状态类的方法。
**/
@Slf4j
public class Room{
State state;
/**
* 状态模式特点一、除了关联抽象状态,还需要关联我们具体状态
*/
State freeState;
State reservationState;
State checkinState;
//初始化全部状态,且绑定关系
public Room() {
freeState = new FreeState(this);
reservationState = new ReservationState(this);
checkinState = new CheckinState(this);
state = freeState;
}
public void setState(State state) {
this.state = state;
}
/**
* 核心方法
* @return
*/
public State getState() {
return state;
}
public void setFreeState(State freeState) {
this.freeState = freeState;
}
public void setReservationState(State reservationState) {
this.reservationState = reservationState;
}
public void setCheckinState(State checkinState) {
this.checkinState = checkinState;
}
public void reservationRoom() {
state.reservationRoom();
}
public void unsubscribeRoom() {
state.unsubscribeRoom();
}
public void checkinRoom() {
state.checkinRoom();
}
public void checkoutRoom() {
state.checkoutRoom();
}
public void showCurrState(){
log.info("当前房间状态 {}", this.state.getClass().getSimpleName());
}
}
- 测试类
public class Test {
public static void main(String[] args) {
Room room = new Room();
room.reservationRoom();
room.showCurrState();
room.checkinRoom();
room.showCurrState();
room.checkinRoom();
room.checkoutRoom();
room.showCurrState();
}
}
输出结果:
FreeState - 您已预定房间
Room - 当前房间状态 ReservationState
ReservationState - 您已入住成功
Room - 当前房间状态 CheckinState
CheckinState - 入住失败,该房间已经入住
CheckinState - 您已退房
Room - 当前房间状态 FreeState
优点
- 状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足“单一职责原则”。
- 减少对象间的相互依赖。将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖。
- 有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换。
缺点
- 状态模式的使用必然会增加系统的类与对象的个数。
- 状态模式的结构与实现都较为复杂。
适用场景
- 当对象的状态很多时,程序会变得很复杂。而且增加新的状态要添加新的 if-else 语句,这违背了“开闭原则”,不利于程序的扩展。
- 对象的行为依赖于它的状态并且可以根据它的状态改变而改变它的相关行为。
总结
- 状态模式允许一个对象基于内部状态而拥有不同的行为。
- Context会将行为委托给当前状态对象。