状态模式
发布日期:2021-05-09 00:05:13 浏览次数:21 分类:博客文章

本文共 4047 字,大约阅读时间需要 13 分钟。

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

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

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

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设计模式>>

<<大话设计模式>>

上一篇:代理模式
下一篇:组合模式

发表评论

最新留言

网站不错 人气很旺了 加油
[***.192.178.218]2025年05月11日 03时59分43秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

2024最火专业解读:信息安全(非常详细)零基础入门到精通,收藏这一篇就够了 2025-03-29
(插播)unity的 异常捕捉和 ios Android 崩溃信息的捕捉。 2025-03-29
2024版最新SRC漏洞挖掘思路手法(非常详细),零基础入门到精通,收藏这一篇就够了 2025-03-29
2024版最新渗透测试零基础入门教程,带你入门到精通(超详细),收藏这篇就够了 2025-03-29
2024版最新网络安全入门必备读书清单(非常详细)零基础入门到精通,收藏这一篇就够了 2025-03-29
2024版最新网络安全教程从入门到精通,看完这一篇就够了 2025-03-29
0/1背包问题——从LeetCode题海中总结常见套路 2025-03-29
(原创)面向对象的系统对接接口编写。第5篇(完结) 2025-03-29
2024网络安全岗就业前景如何?零基础入门到精通,收藏这篇就够了 2025-03-29
2024零基础如何入门网络安全? 2025-03-29
2024,java开发,已经炸了吗? 2025-03-29
2025入门黑客技术必读书籍(非常全面)带你从小白进阶大佬!收藏这一篇就够了 2025-03-29
2025入门黑客技术必读书籍(非常全面)带你从小白进阶大佬!收藏这篇就够了 2025-03-29
2025大语言模型入门该怎么学?零基础入门到精通,收藏这篇就够了 2025-03-29
2025年3月全国计算等级考试(报名操作指南)从零基础到精通,收藏这篇就够了! 2025-03-29
2025年中国云计算市场四大趋势前瞻,从零基础到精通,收藏这篇就够了! 2025-03-29
.off打开方式、文件格式和使用代码(Python示例) 2025-03-29
2025年十大最佳漏洞管理工具,从零基础到精通,收藏这篇就够了! 2025-03-29
2025年网络安全五大趋势与十大威胁预测,从零基础到精通,收藏这篇就够了! 2025-03-30
2025想做黑客?先来学习 SQL 注入,零基础入门到精通,收藏这篇就够了 2025-03-30