Skip to content

状态模式

ZHI-XINHUA edited this page Jan 11, 2019 · 1 revision

状态模式(state)

状态模式允许一个对象在其内部状态改变的时候改变其行为。把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类。

状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。

核心: 用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题。

1、角色

  • 抽象状态(State)角色:定义一个接口,用以封装环境(Context)对象的一个特定的状态所对应的行为
  • 具体状态(ConcreteState)角色:每一个具体状态都实现了环境(Context)的一个状态所对应的行为。
  • 环境(Context)角色:环境类中维护一个State对象,他是定义了当前的状态。

uml:

2、酒店预订房间demo

场景如下:

  房间状态:空闲、已预订、已入住;不同的状态其行为不一样。 没有使用状态模式情况下,业务逻辑可能如右边的写法,太多的if else判断,扩展性不高。

使用状态模式实现酒店预订的例子

uml图如下:

(1)抽象一个房间状态角色 State,提供一个不同状态下可操作的方法

/**
 * 抽象状态(State)角色:定义一个状态接口,用以封装环境(Context)对象的一个特定的状态所对应的行为
 */
public interface State {
    //不同状态,会有不同的操作
    void operation();
}

(2)实现三种状态下的具体实现及对应行为

房间空闲状态 FreeState:

/**
 * 房间空闲状态
 * 具体状态(ConcreteState)角色:每个具体状态都实现了所对应的行为
 */
public class FreeState implements State {
    @Override
    public void operation() {
        System.out.println("房间处于空闲状态,可接受预定!");
    }
}

房间已预订状态 BookedState:

/**
 * 房间已预定状态
 */
public class BookedState implements State
{
    @Override
    public void operation() {
        System.out.println("房间已预定,请不要接受其它预定");
    }
}

房间已入住状态 CheckedInState:

/**
 * 房间已入住状态
 */
public class CheckedInState implements State {
    @Override
    public void operation() {
        System.out.println("房间已有客人入住,请不要打扰!");
    }
}

(3)房间(Context上下文) 维护状态

/**
 * 房间
 * 环境(Context)角色:维护一个状态(State)对象,定义了当前的状态
 */
public class RoomContext {
    private State state;

    public void setState(State state){
        System.out.println("房间状态已改变");
        this.state = state;
    }

    /**
     * 行为操作
     */
    public void useSituation(){
        state.operation();
    }
}

(4)测试

public class Client {
    public static void main(String[] args) {
        //设置房间(context)
        RoomContext context = new RoomContext();
        //改变状态
        context.setState(new BookedState());
        context.useSituation();

        //改变状态
        context.setState(new CheckedInState());
        context.useSituation();

        //改变状态
        context.setState(new FreeState());
        context.useSituation();

    }
}
房间状态已改变
房间已预定,请不要接受其它预定
房间状态已改变
房间已有客人入住,请不要打扰!
房间状态已改变
房间处于空闲状态,可接受预定!

3、开发中常见的场景

  • 银行系统中账号状态的管理
  • OA系统中公文状态的管理
  • 酒店系统中,房间状态的管理
  • 线程对象各状态之间的切换

4、状态模式和策略模式的区别

状态模式和策略模式很容易混淆,都是context上下文根据不同的实现做出不同的行为。uml都是如下:

     一个简单的区别方法是观察环境角色是否有明细的状态和状态的过度。如果环境角色只有一个状态,那么就是策略模式。策略模式的特点是:一旦环境角色选择了一个具体的策略类,那么在整个环境类的生命周期里它都不会改变这个具体策略类。而状态模式有明显的状态转移,在环境类的生命周期里会有不同状态的对象被使用。

     策略模式的环境类自己选择一个具体策略类;而状态模式的环境类是被外在原因放进一个具体状态中。

所以,策略模式的context是构造器注入具体策略

public class Context {
    private Calculator calculator;

    public Context(Calculator calculator){
        this.calculator = calculator;
    }

    public int executeCalculate(int num1,int num2){
        return calculator.calculate(num1,num2);
    }
}
//加法计算
Context c1 = new Context(new AddCalculator());
int result1 = c1.executeCalculate(2,3);
System.out.println(result1);

//减法计算
Context c2 = new Context(new SubCalculator());
int result2= c1.executeCalculate(2,3);
System.out.println(result2);

而状态模式context是提供修改状态的方法:

public void setState(State state){
    System.out.println("房间状态已改变");
    this.state = state;
}