- 状态模式
状态模式允许一个对象在其内部状态发送改变时,改变其行为,看上去就像是改变了他的类一样。
状态模式要求我们把对象的行为放到对象不同的状态中。随着状态的改变对象的行为也随之发生改变。另外重要的一点是,我们研究的对象要持有所有的状态,在状态类中是通过对象来改变其自身的状态的。 - 状态模式的示意图
- 状态模式包含的角色
环境角色:持有所有自身所有的状态。而且,该类中也定义了当前对象转换状态的操作。也就是通过这些方法来返回当前对象的具体状态。
**抽象状态角色:**定义一个接口供所有具体状态实现。里面定义了状态转换的操作方法。也就是一系列动作,例如:酒店需要通过预定或者入住,才能将房间的状态的转变为已预订状态和已入住状态,这里的预定和入住的方法就需要定义在这个抽象角色中,供具体状态角色实现。
具体状态角色:持有环境角色。 每个具体状态角色都实现了该状态下,环境角色的所有行为。 - 状态模式示例代码
场景:日常生活中餐厅为例,你如果想去吃饭,则需要提前预定,然后前往吃饭,吃完饭付完钱就可以释放当前餐桌。既然预定了,也可以退订。这里涉及到的餐桌状态就有,已预订状态,已占用状态(这里占用指的是现场有人在吃饭!),空闲状态。
注意:在这里我们要分清楚对象的状态和改变对象状态的操作。
环境角色: (餐桌)
public class Table {
public State bookedState;
public State freeState;
public State occupiedState;
private State state ;
public Table() {
bookedState = new BookedState(this);
freeState = new FreeState(this);
occupiedState = new OccupiedState(this);
state = freeState;//初始为空闲
}
public void setState(State state) {
this.state = state;
}
/**
* 预定
*/
public void book(){
state.book();
}
/**
* 退订
*/
public void Unsubscribe(){
state.Unsubscribe();
}
/**
* 吃饭
*/
public void eat(){
state.eat();
}
/**
* 付钱走人
*/
public void payMoneyAndLeave(){
state.payMoneyAndLeave();
}
}
抽象状态角色:
public interface State {
/**
* 预定
*/
void book();
/**
* 退订
*/
void Unsubscribe();
/**
* 吃饭
*/
void eat();
/**
* 付钱走人
*/
void payMoneyAndLeave();
}
具体状态角色:(各种状态)
空闲状态:
public class FreeState implements State {
private Table table;
public FreeState(Table table) {
this.table = table;
}
@Override
public void book() {
System.out.println("您已经成功预订了...");
table.setState(table.bookedState);
}
@Override
public void Unsubscribe() {
}
@Override
public void eat() {
System.out.println("您已经成功开始等菜...");
table.setState(table.occupiedState);
}
@Override
public void payMoneyAndLeave() {
}
}
预定状态:
public class BookedState implements State{
private Table table;
public BookedState(Table table) {
this.table = table;
}
@Override
public void book() {
}
@Override
public void Unsubscribe() {
System.out.println("您已经成功取消预订了...");
table.setState(table.freeState);
}
@Override
public void eat() {
System.out.println("您已经到达餐厅吃饭...");
table.setState(table.occupiedState);
}
@Override
public void payMoneyAndLeave() {
}
}
占用状态:(指到现场吃饭)
public class OccupiedState implements State {
private Table table;
public OccupiedState(Table table) {
this.table = table;
}
@Override
public void book() {
}
@Override
public void Unsubscribe() {
System.out.println("您已经成功取消了预订了...");
table.setState(table.freeState);
}
@Override
public void eat() {
}
@Override
public void payMoneyAndLeave() {
System.out.println("您已经付完钱离开...");
table.setState(table.freeState);
}
}
测试主函数:
public class Main {
public static void main(String[] args) {
Table table = new Table();
table.book();
table.eat();
table.payMoneyAndLeave();
System.out.println("----------------------------------");
table.eat();
table.payMoneyAndLeave();
}
}
- 状态模式的优缺点
- 优点:
- 封装了转换规则。
- 枚举了对象几乎所有的状态。
- 将所有与某个状态相关的行为或者是方法放到一个类中,可以很方便的增加新的状态,只需要该表状态的行为即可。
- 减少了代码中的if…else…的使用。
- 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
- 缺点:
- 会增加系统的类和对象的个数。
- 状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。
- 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。