状态模式

PPG007 ... 2021-12-30 About 2 min

# 状态模式

# 定义

当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。

核心是封装,状态的变更引起行为的变更,从外部看起来就好像这个对象对应的类发生了改变一样。

# 角色

  • State 抽象状态角色:接口或抽象类,负责对象状态定义,并且封装环境角色以实现状态切换。
  • ConcreteState 具体状态角色:每一个具体状态必须完成两个职责,本状态的行为管理以及趋向状态处理,即本状态要做的事和如何过渡到其他状态。
  • Context 环境角色:定义客户端需要的接口,并且负责具体状态的切换。

# 示例

抽象状态角色:

public abstract class State {

    protected Context context;

    public void setContext(Context context) {
        this.context = context;
    }

    /**
     * 行为1
     */
    public abstract void handle1();

    /**
     * 行为2
     */
    public abstract void handle2();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

抽象环境角色:

public class Context{

    public final static State STATE_1=new ConcreteState1();

    public final static State STATE_2=new ConcreteState2();

    private State currentState;

    public State getCurrentState() {
        return currentState;
    }

    public void setCurrentState(State currentState) {
        this.currentState = currentState;
        //每个状态都绑定当前环境对象
        this.currentState.setContext(this);
    }

    public void handle1() {
        this.currentState.handle1();
    }

    public void handle2() {
        this.currentState.handle2();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

具体状态角色:

public class ConcreteState1 extends State{
    @Override
    public void handle1() {
        System.out.println(this.getClass().getName()+"is handling");
    }

    @Override
    public void handle2() {
        this.context.setCurrentState(Context.STATE_2);
        this.context.handle2();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
public class ConcreteState2 extends State{
    @Override
    public void handle1() {
        this.context.setCurrentState(Context.STATE_1);
        this.context.handle1();
    }

    @Override
    public void handle2() {
        System.out.println(this.getClass().getName()+"is handling");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12

在调用自己无法完成的方法时,进行状态切换并调用可用实现。

启动类:

public class Client {
    public static void main(String[] args) {
        Context context = new Context();
        context.setCurrentState(new ConcreteState1());
        context.handle1();
        context.handle2();
    }
}
1
2
3
4
5
6
7
8

# 状态模式的优点

  • 结构清晰,避免了过多的分支语句。
  • 遵循设计原则,很好的体现了开闭原则和单一职责原则。
  • 封装性好,状态变换发生在类的内部。

# 状态模式的缺点

子类太多容易出现类膨胀。

# 状态模式的使用场景

  • 行为随状态改变而改变的场景,例如权限设计。
  • 条件、分支判断语句的替代者。

# 状态模式注意事项

使用时对象的状态最好不要超过五个。

Last update: December 30, 2021 09:14
Contributors: PPG007