13.状态模式

1.什么是状态模式?

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

2.通过实际的需求来理解状态模式

2.1 一份来自万能糖果公司的需求

万能糖果公司正在研发最新的糖果机,他们的糖果机的工程师设计了如下状态转换图:
在这里插入图片描述

他们希望我们用java语言将这个状态转换图描述的功能实现,而且希望我们设计的有弹性一点,因为他们将来可能需要根据需求对其进行修改。

老板接到了这个活后,将这个任务交给了一位新手去设计实现,因为他想锻炼一下这位新手员工A。
员工A拿到状态转换图后,好像有点迷糊,他不知道怎么去看这个图,这时,他向组长请教:我该如何去看这个状态转换图的,哪里是开始?哪里是结束?
组长提示他说:你想象一下如果在你面前是个真实的糖果机,你要如何开始? 怎么结束?

2.1.1 员工A对需求的理解以及设计

员工A听完,醍醐灌顶,于是他梳理出来这个状态转换图的标准流程:

  • 首先最开始糖果机是没有糖果的,它应该位于糖果买完了的状态,然后当工作人员放入糖果后,糖果机才进入没有硬币的状态,所以这里应该是糖果机的工程师漏了一个步骤。
  • 然后当用户向糖果机投入一枚硬币后,糖果机进入有一枚硬币的状态,这时,用户可以拉动拉杆了。
  • 接着当用户拉动拉杆后,糖果机进入卖出糖果的状态,然后需要吐出一枚糖果,然后糖果机就要进行判断剩余糖果数量了,如果剩余糖果数量=0了,则需要进入糖果买完了的状态,否则就要重新进入没有硬币的状态了。

完整的状态流程图如下:
在这里插入图片描述
员工A理解的需求,他开始进行程序设计了,他不假思索,很快就给出了如下设计:
在这里插入图片描述
其中常量 SOLD_OUT, NO_QUARTER , HAS_QUARTER,SOLD分别标志着糖果机的四种状态。
变量 state代表着糖果机的最新状态,count代表着糖果机的糖果的数量。

方法如下:

  • void insertQuarter() 表示投入一枚硬币的动作
  • void ejectQuarter() 表示退回一枚硬币的动作
  • void turnCrank() 表示拉动拉杆的动作
  • void dispense() 表示发放糖果的动作

具体的实现如下:
设计模式/src/main/java/StatePattern/first · 严家豆/设计模式 - 码云 - 开源中国 (gitee.com)

测试方法如下:

package StatePattern.first;

public class FirstTest {

    public static void main(String[] args) {

        GumballMachine gumballMachine = new GumballMachine(2);
        gumballMachine.insertQuarter();
        gumballMachine.turnCrank();

        System.out.println(gumballMachine);

        gumballMachine.ejectQuarter();

        gumballMachine.insertQuarter();
        gumballMachine.insertQuarter();
        gumballMachine.ejectQuarter();
        gumballMachine.turnCrank();

        gumballMachine.insertQuarter();
        gumballMachine.turnCrank();

        gumballMachine.insertQuarter();
        gumballMachine.turnCrank();

    }
}

在这里插入图片描述

当他兴致勃勃的将自己的设计和实现拿给技术总监看时,技术总监却给他泼了一盆冷水:
你确定你的设计满足的客户的需求? 客户说想让我们的设计有弹性,你确定你的设计有弹性? 假如客户需要新加一种状态,你是不是还要打开GumballMachine源码进行修改呢?
致命三连问,问的员工A懵逼了。。。。。。。 看员工A在怀疑人生,总监随即给出一种解决方案: 我建议你用状态模式的角度去看这个需求,也许你会有不同的想法。

2.1.2 用状态模式实现此需求

状态模式允许对象在内部改变时改变它的行为,对象看起来好像修改了它的类。
员工A看完状态模式的定义,还是很懵逼,不解的问总监: 我该如何去下手呢?
总监笑了笑,给了他一个接口:
在这里插入图片描述

员工A看到这个接口,回去苦思冥想,终于他悟了: 将每个状态当作一个类去设计,然后在GumballMachine去组合它进行使用,这样的话,当新增一个状态,我们就不需要去修改现有的类了,而只需要新增一个类实现State,然后再GumballMachine去修改对它的使用(而这个方式完全可以做出配置式的)即可。所以,满足了弹性设计的需求。
UML如下:
在这里插入图片描述

代码实现如下:
设计模式/src/main/java/StatePattern/second · 严家豆/设计模式 - 码云 - 开源中国 (gitee.com)

测试方法效果如下:

package StatePattern.second;

/**
 *  状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类
 */
public class SecondTest {
    public static void main(String[] args) {
        GumballMachine gumballMachine = new GumballMachine(3);
        gumballMachine.insertQuarter();
        gumballMachine.ejectQuarter();
        gumballMachine.insertQuarter();
        gumballMachine.turnCrank();
        gumballMachine.turnCrank();
    }
}

在这里插入图片描述

下面再根据上面的设计复习一下状态模式:
状态模式允许对象在内部改变时改变它的行为,对象看起来好像修改了它的类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小牧之

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值