定义
状态模式
状态模式(state pattern):属于对象的行为型模式。又叫状态对象模式(pattern of objects for state);当一个对象的内在状态改变时,允许改变其行为,这个对象看起来像是改变其了类。
涉及的角色
抽象状态(State)角色:定义一个接口,用以封装环境(Context)对象的一个特定的状态相关的行为。
环境(Context)角色:维护一个具体状态(ConcreteState)实例,这个实例定义当前的状态。
具体状态(ConcreteState)角色:每一个具体状态(ConcreteState)实例都实现了与环境(Context)对象的一个状态相关的行为。
例子
例如:酒店有预定,退订,入住和退房等各种状态。
状态流转图如下:
每个单元代表一种状态,箭头指向代表房间的状态转换。
酒店的UML类图:
抽象状态(State)角色:对应的状态接口:
public interface State {
/**
* @desc 预订房间
* @return void
*/
public void bookRoom();
/**
* @desc 退订房间
* @return void
*/
public void unsubscribeRoom();
/**
* @desc 入住
* @return void
*/
public void checkInRoom();
/**
* @desc 退房
* @return void
*/
public void checkOutRoom();
}
房间类:
public class Room {
/*
* 房间的三个状态
*/
State freeTimeState; //空闲状态
State checkInState; //入住状态
State bookedState; //预订状态
State state ;
public Room(){
freeTimeState = new FreeTimeState(this);
checkInState = new CheckInState(this);
bookedState = new BookedState(this);
state = freeTimeState ; //初始状态为空闲
}
/**
* @desc 预订房间
* @return void
*/
public void bookRoom(){
state.bookRoom();
}
/**
* @desc 退订房间
* @return void
*/
public void unsubscribeRoom(){
state.unsubscribeRoom();
}
/**
* @desc 入住
* @return void
*/
public void checkInRoom(){
state.checkInRoom();
}
/**
* @desc 退房
* @return void
*/
public void checkOutRoom(){
state.checkOutRoom();
}
public String toString(){
return "该房间的状态是:"+getState().getClass().getName();
}
/*
* getter和setter方法略
*/
...
}
三个状态类:
//预定状态房间只能退定
public class BookedState implements State {
Room hotelManagement;
public BookedState(Room hotelManagement) {
this.hotelManagement = hotelManagement;
}
public void bookRoom() {
System.out.println("该房间已近给预定了...");
}
public void checkInRoom() {
System.out.println("入住成功...");
hotelManagement.setState(hotelManagement.getCheckInState()); //状态变成入住
}
public void checkOutRoom() {
//不需要做操作
}
public void unsubscribeRoom() {
System.out.println("退订成功,欢迎下次光临...");
hotelManagement.setState(hotelManagement.getFreeTimeState()); //变成空闲状态
}
}
//入住可以退房
public class CheckInState implements State {
Room hotelManagement;
public CheckInState(Room hotelManagement) {
this.hotelManagement = hotelManagement;
}
public void bookRoom() {
System.out.println("该房间已经入住了...");
}
public void checkInRoom() {
System.out.println("该房间已经入住了...");
}
public void checkOutRoom() {
System.out.println("退房成功....");
hotelManagement.setState(hotelManagement.getFreeTimeState()); //状态变成空闲
}
public void unsubscribeRoom() {
//不需要做操作
}
}
//空闲状态只能预订和入住
public class FreeTimeState implements State {
Room hotelManagement;
public FreeTimeState(Room hotelManagement){
this.hotelManagement = hotelManagement;
}
public void bookRoom() {
System.out.println("您已经成功预订了...");
hotelManagement.setState(hotelManagement.getBookedState()); //状态变成已经预订
}
public void checkInRoom() {
System.out.println("您已经成功入住了...");
hotelManagement.setState(hotelManagement.getCheckInState()); //状态变成已经入住
}
public void checkOutRoom() {
//不需要做操作
}
public void unsubscribeRoom() {
//不需要做操作
}
}
测试类:
public class Test {
public static void main(String[] args) {
//有2间房
Room[] rooms = new Room[2];
//初始化
for(int i = 0 ; i < rooms.length ; i++){
rooms[i] = new Room();
}
//第一间房
rooms[0].bookRoom(); //预订
rooms[0].checkInRoom(); //入住
rooms[0].bookRoom(); //预订
System.out.println(rooms[0]);
System.out.println("---------------------------");
//第二间房
rooms[1].checkInRoom();
rooms[1].bookRoom();
rooms[1].checkOutRoom();
rooms[1].bookRoom();
System.out.println(rooms[1]);
}
}
总结
状态模式应用
当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式了。
状态模式优点
状态模式将与特定状态相关的行为局部化,并且将不同状态的行为分割开来。也就是说可以将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在于某个 ConcreteState 中,所以通过定义新的子类可以很容易地增加行的状态和转换。这样可以消除庞大的条件分支语句。
状态模式通过把各种状态转移逻辑分布到 State 的子类之间,来减少相互间的依赖。