状态模式:允许对象在内部状态发生改变时改变他的行为,对象看起来好像修改了它的类。
状态模式的uml图如下:
状态模式包括以下角色:
Context类:环境类,包括一些内部状态。
State类—抽象状态类,state定义的一个所有的具体状态的共同接口,任何状态都能实现这个接口,这样一来状态之间可以互相转换。
ConcreteState类:具体的状态类。用于处理来自Context的请求,每一个ConcreteState都实现了context一个状态相关的行为,所以当context改变状态时,行为也会跟着改变。
例如,酒店的房间有预定,退订,入住,退房等各种状态。
每一个单元代表房间的一种状态,箭头指向代表房间状态的转换。
酒店的uml图:
对应的状态接口:
package com.hy.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();
}
房间类:
package com.hy.state;
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方法略
*/
...
}
三个状态类:
package com.hy.state;
/**
* @project: design_state
* @date 2013-8-24
* @Description: 预定状态房间只能退定
*/
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()); //变成空闲状态
}
}
package com.hy.state;
/**
* @project: design_state
* @date 2013-8-24
* @Description: 入住可以退房
*/
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() {
//不需要做操作
}
}
package com.hy.state;
/**
* @project: design_state
* @date 2013-8-24
* @Description: 空闲状态只能预订和入住
*/
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() {
//不需要做操作
}
}
测试类:
package com.hy.state;
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的子类之中,来减少相互之间的依赖。
注意:使用前需要枚举可能的状态,否则可能也会有一些工作量。例如新增一个预留状态,除了新增一个预留状态ConcreteState类,还需要在状态State接口中新增预留接口,Room类中新增预留状态,各个ConcreteState接口类增加与预留状态相互的关系行为。
这也大致体现了状态模式的缺点,必然性的会增加系统中类和对象的个数。使用不当会导致系统的复杂性增加。如果预先状态设计不能全面,对开闭原则支持的就不太好,对于互相切换状态的系统,新增新的状态会修改那些负责状态转换和对应类的代码。