• 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();
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    在这里插入图片描述

    当他兴致勃勃的将自己的设计和实现拿给技术总监看时,技术总监却给他泼了一盆冷水:
    你确定你的设计满足的客户的需求? 客户说想让我们的设计有弹性,你确定你的设计有弹性? 假如客户需要新加一种状态,你是不是还要打开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();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在这里插入图片描述

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

  • 相关阅读:
    一键上手时下最火AI作画工具
    SVM支持向量机
    进程线程协程补充、docker-compose一键部署项目、搭建代理池、requests超时设置、认证设置、异常处理、上传文件
    第三十四章 Objects - 流接口类
    使用vim对比两个文件
    Chrome Thems 介绍
    手绘板的制作——重置与橡皮擦(2)
    实战项目:物流行业数据分析
    计算机网络第2章-HTTP和Web协议(2)
    Eigen
  • 原文地址:https://blog.csdn.net/c1776167012/article/details/125440119