• 状态模式


          状态模式,顾名思义,重点关注对象的各种状态。状态模式将对象的每一种状态独立成类,同时将对象的行为委托给对应的状态类执行。它的优点在于,当需要增加或者减少对象的状态时,只需要增加减少状态类,并修改少量的代码就能实现。

          本文将采用状态模式和非状态模式分别实现同一个例子,以讲解状态模式的用法以及使用状态模式的好处。

          例子很简单,我们想用程序来模拟人在不同负重下的行走和奔跑行为,负重越少,行走和奔跑就越轻松;负重越多行走和奔跑则愈发费劲,甚至根本就跑不动。

    1. 普通方式实现人在不同负重下的行走和奔跑行为

          首先采用最平常的方式来实现行走和奔跑的设计:

    public class Human {
      private double weight;  //体重
      private double weightBearing;  //负重
    
      public Human(double weight){
        this.weight = weight;
      }
    
      public void setWeightBearing(double weightBearing){
        this.weightBearing = weightBearing;
      }
    
      public double getRate(){
        return weightBearing / weight;
      }
    
      public void walk(){
        double rate = getRate();
        if(rate < 0.2){
          System.out.println("轻轻松松地走。。。");
        }else if(rate < 0.6){
          System.out.println("气喘吁吁地走。。。");
        }else{
          System.out.println("只能慢慢走。。。");
        }
      }
    
      public void run(){
        double rate = getRate();
        if(rate < 0.2){
          System.out.println("一路小跑。。。");
        }else if(rate < 0.6){
          System.out.println("象征性地跑。。。");
        }else{
          System.out.println("跑不动。。。");
        }
      }
    }

          然后测一测代码的效果:

    public class StatePatternTest {
      public static void main(String[] args){
        StatePatternTest test = new StatePatternTest();
        test.normalTest();
      }
      public void normalTest(){
        Human human = new Human(150);
        human.walk();
        human.run();
        human.setWeightBearing(50);
        human.walk();
        human.run();
        human.setWeightBearing(100);
        human.walk();
        human.run();
      }
    }

          输出如下:

    轻轻松松地走。。。
    一路小跑。。。
    气喘吁吁地走。。。
    象征性地跑。。。
    只能慢慢走。。。
    跑不动。。。

          代码看起来没有问题,不过我们发现,负重比在大于60%这个区间还可以进一步细化,因为负重越大,对体能影响越大,这个时候每增加10%可能都会有不一样的结果。对于这样的细化要求,我们需要修改上面每个方法里的分支语句,并且随着以后的细化需求越来越多,分支会越来越长,不利于维护。

          通过观察分析,我们发现,不同的区间对应不同的行为,可以根据区间进行划分,每个区间实现自己的walk()和fun()方法,对于Human对象来说,不需要知道现在是处在哪个负重区间,只需要将行为委托给区间对象去处理就行了。在这里,我们称不同的区间为不同的状态,所有的状态实现或者继承同一个State对象。

          接下来,我们准备使用状态模式重新实现行走和奔跑的设计,在继续进行下去之前,先给出状态模式的定义。

    2. 状态模式的定义

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

          定义的第一部分说的是状态改变的时候,对象的行为也会随之改变,在我们的例子中,负重改变时,行走和奔跑的行为会有不同的表现;定义的第二部分是说,状态改变的时候对象发生对应的改变,在外界看起来,好像是在跟一个新的类打交道,实际上我们知道,对象还是那个对象,只是底层的实现改变了而已。

    3. 采用状态模式的实现

          下面将使用状态模式来重新设计,首先定义统一的状态接口State:

    public interface State {
      void walk();
      void run();
    }

          根据不同的负重定义三种负重状态:

    //轻度负重类
    public class SlightlyOverWeighted implements State {
    
      private SmartHuman human;
    
      public SlightlyOverWeighted(SmartHuman human){
        this.human = human;
      }
    
      @Override
      public void walk() {
        if(human.getRate() < 0.2){
          System.out.println("轻轻松松地走。。。");
        }else{
          human.setState(new MiddleOverWeighted(human));
          human.walk();
        }
      }
    
      @Override
      public void run() {
        if(human.getRate() < 0.2){
          System.out.println("一路小跑。。。");
        }else{
          human.setState(new MiddleOverWeighted(human));
          human.run();
        }
      }
    }
    //中度负重类
    public class MiddleOverWeighted implements State{
      private SmartHuman human;
    
      public MiddleOverWeighted(SmartHuman human){
        this.human = human;
      }
    
      @Override
      public void walk() {
        if(human.getRate() < 0.6){
          System.out.println("气喘吁吁地走。。。");
        }else{
          human.setState(new OverWeighted(human));
          human.walk();
        }
      }
    
      @Override
      public void run() {
        if(human.getRate() < 0.6){
          System.out.println("象征性地跑。。。");
        }else{
          human.setState(new OverWeighted(human));
          human.run();
        }
      }
    }
    //超重类
    public class OverWeighted implements State{
      private SmartHuman human;
    
      public OverWeighted(SmartHuman human){
        this.human = human;
      }
    
      @Override
      public void walk() {
        System.out.println("只能慢慢走。。。");
      }
    
      @Override
      public void run() {
        System.out.println("跑不动。。。");
      }
    }

          下面测试一下采用状态模式的实现:

    public class StatePatternTest {
      public static void main(String[] args){
        StatePatternTest test = new StatePatternTest();
        test.statePatternTest();
      }
    
      public void statePatternTest(){
        SmartHuman human = new SmartHuman(150);
        human.walk();
        human.run();
        human.setWeightBearing(50);
        human.walk();
        human.run();
        human.setWeightBearing(100);
        human.walk();
        human.run();
      }
    }

          输出为:

    轻轻松松地走。。。
    一路小跑。。。
    气喘吁吁地走。。。
    象征性地跑。。。
    只能慢慢走。。。
    跑不动。。。

    4. 总结

          新的测试类几乎与之前的测试一模一样,而且结果也符合预期。当我们想喜欢负重状态时,只需要增加对应的状态类,然后修改相邻状态类的少量代码即可。从上面的代码总结出状态模式的类图结构如下:

     5. 参考文献

    <<Head First设计模式>>

    <<大话设计模式>>

  • 相关阅读:
    替代PhotoShop:GIMP图形编辑器的使用
    Matlab: 主函数和子函数间接传递变量
    代码管理:SVN的使用
    Python: 科学计算
    Python: 代码调试
    Latex: article模板
    Matlab: 程序优化和调试
    LibreOffice的使用技巧
    mysql--多表联合查询
    mysql--数据查询
  • 原文地址:https://www.cnblogs.com/NaLanZiYi-LinEr/p/11704960.html
Copyright © 2020-2023  润新知