博客信息

状态模式State(行为模式)

发布时间:『 2019-03-30 03:27』  博客类别:23种设计模式  阅读(826)
  • 术语

    State:状态

  • 角色

    Context:环境角色:用于维护 State 实例,这个实例定义当前状态 State:抽象状态角色:聚合到Context环境角色中 ConcreteState :具体的状态角色 ConcreteStateA ConcreteStateB ConcreteStateC

UML类图

小李飞刀_设计模式



案例

案例:抽奖活动项目设计

小李飞刀_设计模式


    • 出现前

    package com.javaxl.design.state.before;

    import java.util.Random;

    /**
    * @author 小李飞刀
    * @site www.javaxl.com
    * @company
    * @create  2020-02-25 12:57
    */
    public class State {
      //   当前的状态
      private int state;
      //   供抽奖的积分
      private int score;
      //   奖品的数量
      private int count;

      public State(int score, int count) {
          this.score = score;
          this.count = count;
      }

      public int getCount() {
          return count;
      }

      public int getState() {
          return state;
      }

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

      public int getScore() {
          return score;
      }

      public void setScore(int score) {
          this.score = score;
      }

      //   扣除积分
      public void minus() {
    //       只有一阶段可以扣积分
          this.state = 1;
          if (this.state == 1) {
              if (this.score >= 50) {
                  if (this.count == 0) {
                      System.out.println("奖品领完....");
                      return;
                  }
                  this.score = this.score - 50;
                  System.out.println("========扣除50积分,当前积分还剩" + this.score + "========");
                  this.state = 2;
                  if (luckHit()) {
                      this.state = 3;
                      getPrize();
                  }
              } else {
                  System.out.println("========积分不够,当前积分为" + this.score + "========");
              }
          }

      }

      //   十分之一抽中奖品的概率
      public boolean luckHit() {
    //       只有二阶段可以抽奖
          return this.state == 2 ? (new Random().nextInt(10) == 6) : false;
      }

      public void getPrize() {
          if (this.state == 3) {
              if (this.count > 0) {
                  System.out.println("领取奖品....");
                  this.count = this.count - 1;
              } else {
                  System.out.println("奖品领完....");
              }
          }
      }

    }


    public class Client {
      public static void main(String[] args) {
          State state = new State(500,1);
    //       state.minus();
          for (int i = 0; i < 300; i++) {
              state.minus();
          }
      }
    }

    从上面的编码中,我们可以看出,完成该需求有很多的条件判断,非常不利于后续的维护;上面状态只有4个,代码已经比较复杂了;状态越多,代码嵌套就越复杂,维护成本就越高;

    • 出现后

package com.javaxl.design.state.after;

import java.util.Random;

/**
* @author 小李飞刀
* @site www.javaxl.com
* @company
* @create  2020-02-25 15:59
*/
public abstract class State {

//   扣积分
  abstract void minus();
//   抽奖
  abstract boolean luckHit();
//   获取奖品
  abstract void getPrize();

}

class ConcreteStateA extends State{
  Context context;

  public ConcreteStateA(Context context) {
      this.context = context;
  }

  @Override
  void minus() {
      if(context.getScore()>=50){
          context.setScore(context.getScore()-50);
          System.out.println("========扣除50积分,当前积分还剩"+context.getScore()+"========");
          context.setState(context.getStateB());
      }else{
          System.out.println("========积分不够,当前积分为"+context.getScore()+"========");
      }
  }

  @Override
  boolean luckHit() {
      System.out.println("还在扣费环节,不能抽奖...");
      return false;
  }

  @Override
  void getPrize() {
      System.out.println("还在扣费环节,不能领取奖品...");
  }
}

class ConcreteStateB extends State{
  Context context;

  public ConcreteStateB(Context context) {
      this.context = context;
  }

  @Override
  void minus() {
      System.out.println("已经在抽奖环节...");
  }

  @Override
  boolean luckHit() {
      boolean flag = new Random().nextInt(10) == 6;
      if(flag){
          context.setState(context.getStateC());
      }else{
          context.setState(context.getStateA());
      }
      return flag;
  }

  @Override
  void getPrize() {
      System.out.println("还在抽奖环节,不能领取奖品...");
  }
}

class ConcreteStateC extends State{
  Context context;

  public ConcreteStateC(Context context) {
      this.context = context;
  }

  @Override
  void minus() {
      System.out.println("已经在领取奖品环节...");
  }

  @Override
  boolean luckHit() {
      System.out.println("已经在领取奖品环节...");
      return false;
  }

  @Override
  void getPrize() {
      if(context.getCount()>0){
          System.out.println("领取奖品成功...");
          context.setState(context.getStateA());
      }else {
          System.out.println("活动结束,领取奖品失败...");
          context.setState(context.getStateD());
//           不继续抽奖
//           System.exit(0);
      }
  }
}

class ConcreteStateD extends State{
  Context context;

  public ConcreteStateD(Context context) {
      this.context = context;
  }

  @Override
  void minus() {
      System.out.println("已经在活动结束,奖品送完环节...");
  }

  @Override
  boolean luckHit() {
      System.out.println("已经在活动结束,奖品送完环节...");
      return false;
  }

  @Override
  void getPrize() {
      System.out.println("已经在活动结束,奖品送完环节...");
  }
}


public class Context {
  //   当前的状态
  private State state;
  //   奖品数量
  public int count;
  //   用户积分
  private int score;

  //   表示同一个对象的四种状态
  private ConcreteStateA stateA = new ConcreteStateA(this);
  private ConcreteStateB stateB = new ConcreteStateB(this);
  private ConcreteStateC stateC = new ConcreteStateC(this);
  private ConcreteStateD stateD = new ConcreteStateD(this);


  public Context(int score, int count) {
      this.score = score;
      this.count = count;
      this.state = stateA;
  }

  //   扣积分
  public void minus() {
      state.minus();
  }

  //   抽奖
  public void luckHit() {
      if (state.luckHit()) {
          state.getPrize();
      }
  }

  public State getState() {
      return state;
  }

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

  public int getCount() {
      return count--;
  }

  public void setCount(int count) {
      this.count = count;
  }

  public ConcreteStateA getStateA() {
      return stateA;
  }

  public void setStateA(ConcreteStateA stateA) {
      this.stateA = stateA;
  }

  public ConcreteStateB getStateB() {
      return stateB;
  }

  public void setStateB(ConcreteStateB stateB) {
      this.stateB = stateB;
  }

  public ConcreteStateC getStateC() {
      return stateC;
  }

  public void setStateC(ConcreteStateC stateC) {
      this.stateC = stateC;
  }

  public ConcreteStateD getStateD() {
      return stateD;
  }

  public void setStateD(ConcreteStateD stateD) {
      this.stateD = stateD;
  }

  public int getScore() {
      return score;
  }

  public void setScore(int score) {
      this.score = score;
  }
}


public class Client {
  public static void main(String[] args) {
//       这次游戏积分500个,用完为止,总奖品数2
      Context context = new Context(500,1);
//       context.lunkHit();//还在扣费环节,不能抽奖...

      for (int i = 0; i < 300; i++) {
          context.minus();
          context.luckHit();
      }
      System.out.println("------------------");

  }
}

一次没抽中

小李飞刀_设计模式


抽中一次

小李飞刀_设计模式


抽中两次

小李飞刀_设计模式



  • 注意事项和细节

    • 代码有很强的可读性。状态模式将每个状态的行为封装到对应的一个类中

    • 方便维护。将容易产生问题的 if-else 语句删除了

    • 符合“开闭原则”。容易增删状态

缺点:会产生很多类。每个状态都要一个对应的类,当状态过多时会产生很多类,加大维护难度

应用场景:当一个事件或者对象有很多种状态,状态之间会相互转换,对不同的状态要求有不同的行为的时候, 可以考虑使用状态模式

  • 应用

    借贷平台状态管理


over......


关键字:     设计模式  

备案号:湘ICP备19000029号

Copyright © 2018-2019 javaxl晓码阁 版权所有