1. 概念
对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为
看不懂没关系,看个例子就明白了
2. 一个例子
进程有就绪,运行,停止三个状态(简单起见只说这三个),其状态可以不断从一种转换到另一种,模拟这种情况
2.1 不用设计模式
对于上面的问题,最容易想到的就是在进程类中维护一个状态变量,通过改变这个变量改变状态,并通过对状态变量的判断,执行相对应状态下的操作
class Process{
public static final int READY = 1;
public static final int RUNNING = 2;
public static final int STOP = 3;
private int state;//状态
public void start(){
if(state == READY ){
state = RUNNING;
System.out.println("RUNNING")
}else{
//invalid
}
}
public void stop(){
if(state == RUNNING){
state = STOP;
System.out.println("STOP")
}else{
//invalid
}
}
public void newProcess(){
if(state == STOP){
state = READY ;
System.out.println("READY ")
}else{
//invalid
}
}
}
可以看到这样的实现方法,每个操作都有庞大的分支判断结构,这些分支决定于对象的状态
2.2 使用状态模式改进
如果把进程的状态和当前状态下对应的操作封装到一个类中,再让进程持有这样的状态类,那么就能避免大量的判断,因为每个状态类只操作当前状态下的操作
就像上面所说的,我们在State
的抽象类中把所有的操作都设置为默认非法的,然后再具体的状态去重新当前状态下的操作
状态
abstract class State{
public void newProcess(Process process){
//invalid
}
public void start(Process process){
//invalid
}
public void stop(Process process){
//invalid
}
}
class Stop extends State{
public void newProcess(Process process){
//newProcess
process.setState(new Ready())
}
}
class Ready extends State{
public void start(Process process){
//Ready
process.setState(new Start())
}
}
class Runnable extends State{
public void stop(Process process){
//Stop
process.setState(new Stop())
}
}
Process
class Process{
private State state;
public void setState(State state){
this.state = state;
}
public void stop(Process process){
state.stop(this);
}
public void start(Process process){
state.start(this);
}
public void newProcess(Process process){
state.newProcess(this);
}
}
2.3 引入享元模式
实际上上面的代码有点问题,那就是每次都要创建新的状态对象,这时需要引入享元模式,将这些具体状态对象放在集合中供程序共享
Process
class Process{
Map<Integer, State> map = new HashMap();
private State state;
public Process(){
State ready= new Ready();
map.put(1,ready);
State Runnable= new Runnable();
map.put(2,runnable);
State Stop= new Stop();
map.put(3,stop)
}
public void setState(State state){
this.state = state;
}
public void getState(int key){
state = map.get(key);
}
public void stop(Process process){
state.stop(this);
}
public void start(Process process){
state.start(this);
}
public void newProcess(Process process){
state.newProcess(this);
}
}
状态
abstract class State{
public void newProcess(Process process){
//invalid
}
public void start(Process process){
//invalid
}
public void stop(Process process){
//invalid
}
}
class Stop extends State{
public void newProcess(Process process){
//newProcess
process.setState(process.getState(1))
}
}
class Ready extends State{
public void start(Process process){
//Ready
process.setState(process.getState(2))
}
}
class Runnable extends State{
public void stop(Process process){
//Stop
process.setState(process.getState(3))
}
}
3. 再看概念
状态模式把受环境改变的对象行为包装在不同的状态对象里,其意图是让一个对象在其内部状态改变的时候,其行为也随之改变
- 环境(
Context
)角色:也称为上下文,它定义了客户感兴趣的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理。 - 抽象状态(
State
)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为。 - 具体状态(
Concrete State
)角色:实现抽象状态所对应的行为
状态模式是一种对象行为型模式,其主要优点如下:
- 状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足“单一职责原则”
- 减少对象间的相互依赖。将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖
- 有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换
状态模式的主要缺点如下:
- 状态模式的使用必然会增加系统的类与对象的个数
- 状态模式的结构与实现都较为复杂,如果使用不当会导致程序结构和代码的混乱