设计模式-状态模式(State Pattern)

1,544 阅读5分钟

Github 源码地址

23种设计模式总览

创建型模式

结构型模式

行为型模式

定义

允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。

优缺点

优点:  1、封装了转换规则。 2、枚举可能的状态,在枚举状态之前需要确定状态种类。 3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。 4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。 5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

缺点:  1、状态模式的使用必然会增加系统类和对象的个数。 2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。 3、状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。

使用场景

1、行为随状态改变而改变的场景。
2、条件、分支语句的代替者。

在讲解之前先了解一下一般的状态判断开关切换状态

"一般的状态判断"使用if..else if(条件类型多且复杂可以选择用策略模式),判断条件和state没有关系,代码如下:

if (witch == 'A') {
    state = 'B';
} else if (witch == 'B') {
    state = 'C';
} else if (witch == 'C') {
    state = 'A';
}

"开关切换状态"就是if括号中的"witch"变成"state"

if (state == 'A') {
    state = 'B';
} else if (state == 'B') {
    state = 'C';
} else if (state == 'C') {
    state = 'A';
}

将 state 的状态从"A"切换到"B",再切换到"C";在切换到"A",好象一个旋转开关,这种状态改变就可以使用 State 模式了。

状态模式就是把每一个if语句的状态写成一个子类,用子类来代替一个状态,这个子类包含了这个状态的行为和状态之间的转换。

实现

  • Context(环境类):环境类拥有各种不同状态的对象,作为外部使用的接口,负责调用状态类接口。

  • State(抽象状态):抽象状态既可以为抽象类,也可以直接定义成接口。主要用于定义状态抽象方法,具体实现由子类负责。

  • ConcreteState(具体状态类):具体状态类为抽象状态的实现者,不同的状态类对应这不同的状态,其内部实现也不相同。环境类中使用不同状态的对象时,能实现不同的处理逻辑

一个电视机有两种状态,关机状态和开机状态.关机状态只能开机,开机状态可以上下换台和关机.

抽象状态类

public interface State {

  /**
   * 开机
   */
  void onState();

  /**
   * 关机
   */
   void offState();

  /**
   * 上一个频道
   */
   void previousState();

  /**
   * 下一个频道
   */
   void nextState();
}

电视机类

public class TV {

  //起始状态
  private State state;

  //关机状态
  private State offState;
  //开机状态
  private State onState;

  public TV(){
    offState = new OffState(this);
    onState = new OnState(this);
    
    //起始状态为关机
    state = offState;
  }

  //关机
  public void offState(){
    state.offState();
  }

  //下一个频道
  public void next(){
    state.nextState();
  }

  //上一个频道
  public void previousState(){
    state.previousState();
  }

  //开机
  public void onState(){
    state.onState();
  }

  public State getState() {
    return state;
  }

  public void setState(State state) {
    this.state = state;
  }

  public State getOffState() {
    return offState;
  }

  public void setOffState(State offState) {
    this.offState = offState;
  }

  public State getOnState() {
    return onState;
  }

  public void setOnState(State onState) {
    this.onState = onState;
  }
}

关机状态类

public class OffState implements State {

  TV tv;

  public OffState(TV tv){
    this.tv = tv;
  }

  @Override
  public void onState() {
    System.out.println("电视开机:欢迎~~~");
    //状态变为开机
    tv.setState(tv.getOnState());
  }

  @Override
  public void offState() {
    //无操作
  }

  @Override
  public void previousState() {
    //无操作
  }

  @Override
  public void nextState() {
    //无操作
  }
}

开机状态类

public class OnState implements State{

  TV tv;

  public OnState(TV tv){
    this.tv = tv;
  }

  @Override
  public void onState() {
    //无操作
  }

  @Override
  public void offState() {
    System.out.println("电视关机:欢迎下次观看~~~~~");
    tv.setState(tv.getOnState());
  }

  @Override
  public void previousState() {
    System.out.println("进入------上一个频道");
    tv.setState(tv.getOnState());
  }

  @Override
  public void nextState() {
    System.out.println("进入------下一个频道");
    tv.setState(tv.getOnState());
  }
}

验证

class Test {
    public static void main(String[] args) {
        TV tv = new TV();
        //开机
        tv.onState();
        //下一个频道
        tv.next();
        //上一个频道
        tv.previousState();
        //关机
        tv.offState();
    }
}
电视开机:欢迎~~~
进入------下一个频道
进入------上一个频道
电视关机:欢迎下次观看~~~~~

策略模式和状态模式的对比

  • 策略模式中,类的功能是根据当前条件主动更改;
  • 状态模式中,类的功能是被动由当前状态更改;
  • 策略模式中每个行为或算法之间没有关联;
  • 状态模式中的状态之间有关联,并且状态本身控制着状态转移;