转自:http://www.kongzid.com/archives/design19,更好阅读体验:http://www.kongzid.com
状态模式(State)的定义
状态模式,又称状态对象模式(Pattern of Objects for States),状态模式允许一个对象在其内部状态改变的时候改变其行为。这个对象看上去就像是改变了它的类一样。
用一句话来表述,状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类。状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。
状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。当然,如果这个状态判断很简单,那就没必要用‘状态模式’了。
状态模式(State)优缺点
备忘录模式是一种对象行为型设计模式,其主要优点如下:
- 封装了转换规则。
- 枚举可能的状态,在枚举状态之前需要确定状态种类。
- 将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
- 允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
- 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
缺点:
- 状态模式的使用必然会增加系统类和对象的个数。
- 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
- 状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。
适用环境:
-
代码中包含大量与对象状态有关的条件语句。
-
行为随状态改变而改变的场景。(银行系统中账号状态的管理/OA系统中公文状态的管理/酒店系统中,房间状态的管理/线程对象各状态之间的切换)
在行为受状态约束的时候使用状态模式,而且状态不超过 5 个。
通常命令模式的接口中只有一个方法。而状态模式的接口中有一个或者多个方法。而且,状态模式的实现类的方法,一般返回值,或者是改变实例变量的值。也就是说,状态模式一般和对象的状态有关。实现类的方法有不同的功能,覆盖接口中的方法。状态模式和命令模式一样,也可以用于消除 if...else 等条件选择语句。
状态模式(State)的结构
状态模式所涉及到的角色有:
- 环境(Context)角色,也称上下文:定义客户端所感兴趣的接口,并且保留一个具体状态类的实例。这个具体状态类的实例给出此环境对象的现有状态。
- 抽象状态(State)角色:定义一个接口,用以封装环境(Context)对象的一个特定的状态所对应的行为。
- 具体状态(ConcreteState)角色:每一个具体状态类都实现了环境(Context)的一个状态所对应的行为。
状态模式的应用实例
抽象状态类
public interface State {
/**
* 状态对应的处理
*/
public void handle(String sampleParameter);
}
具体状态类
public class ConcreteStateA implements State {
@Override
public void handle(String sampleParameter) {
System.out.println("ConcreteStateA handle :" + sampleParameter);
}
}
public class ConcreteStateB implements State {
@Override
public void handle(String sampleParameter) {
System.out.println("ConcreteStateB handle :" + sampleParameter);
}
}
环境角色类
public class Context {
//持有一个State类型的对象实例
private State state;
public void setState(State state) {
this.state = state;
}
/**
* 用户感兴趣的接口方法
*/
public void request(String sampleParameter) {
//转调state来处理
state.handle(sampleParameter);
}
}
状态模式的应用实例二
宾馆房间的状态有这么几个:已预订,已入住,空闲。如果不用状态模式我们的实现如下:
if(state=="空闲"){
if(预订房间){
预定操作;
state="已预订";
}else if(住进房间){
入住操作;
state="已入住";
}
}else if(“已预订"){
if(住进房间){
入住操作;
state="已入住";
}else if(取消预订){
取消操作;
state="空闲";
}
}
这种实现中if语句过多,不便于维护修改。这时我们可以考虑用状态模式来实现。
/**
* State 接口
*
*/
public interface State {
void handle();
}
/**
* 已预订状态
*
*/
public class BookedState implements State {
@Override
public void handle() {
System.out.println("房间已预订!别人不能定!");
}
}
/**
* 已入住状态
*
*/
public class CheckedInState implements State {
@Override
public void handle() {
System.out.println("房间已入住!请勿打扰!");
}
}
/**
* 空闲状态
*
*/
public class FreeState implements State {
@Override
public void handle() {
System.out.println("房间空闲!!!没人住!");
}
}
房间对象
/**
* 房间对象
*
*/
public class HomeContext {
//如果是银行系统,这个Context类就是账号。根据金额不同,切换不同的状态!
private State state;
public void setState(State s){
System.out.println("修改状态!");
state = s;
state.handle();
}
}
client
public class Client {
public static void main(String[] args) {
// 获取房间对象
HomeContext ctx = new HomeContext();
// 设置房间状态
ctx.setState(new FreeState());
ctx.setState(new BookedState());
}
}
/**
修改状态!
房间空闲!!!没人住!
修改状态!
房间已预订!别人不能定!
*/