趣解设计模式之《小王的糖果售卖机》

〇、小故事

小王最近一直在寻找商机,他发现商场儿童乐园或者中小学校周围,会有很多小朋友喜欢吃糖果,那么他想设计一款糖果售卖机,让后将这些糖果售卖机布置到商场和学校旁边,这样就能获得源源不断的收益了。

想到这里,说干就干,他绘制出了一台糖果售卖机的操作状态关系流转图,请见下图所示:

如果我们以动作做为一个方法去处理,比如:投入钱币的动作,那么我们就需要按照如下方式去实现方法中的逻辑:

如果已经投了25分钱】提示“已经投入钱币了,你不能再投入钱币了!”;
如果之前没有投过钱】提示“投入钱币成功!”,并且当前的糖果机状态从未投币状态变为已投币状态
如果糖果机里无糖果】提示“糖果已经卖光了,你不能往里投入钱币了!
如果糖果正在出货中】提示“请等一等,糖果正在出货中。你不用在投入钱币了!

针对以上逻辑,代码实现如下所示:

final static int SOLD_OUT = 0; // 糖果售罄
final static int NO_QUARTER = 1; // 没有投入钱币
final static int HAS_QUARTER = 2; // 已经投入钱币
final static int SOLD = 3; // 正在出售糖果public void insertQuarter() {if(state == HAS_QUARTER) {System.out.println("已经投入钱币了,你不能再投入钱币了");} else if(state == NO_QUARTER) {state = HAS_QUARTER;// 将糖果机的状态改为HAS_QUARTER(已投币)System.out.println("投入钱币成功");} if(state == SOLD_OUT) {System.out.println("糖果已经卖光了,你不能往里投入钱币了");} if(state == SOLD) {System.out.println("请等一等,糖果正在出货中。你不用在投入钱币了");}
}

那么其他的动作,比例:转动曲柄退回钱币操作发放糖果等,也需要按照上面的写法去实现逻辑。显然,通过这么一大堆的if...else是不优雅的,而且当增加一个全新的状态的时候,所有的动作都需要兼容这个新的动作,那么,这个就是很明显的基于过程编程了,针对以上的问题,我们可以使用今天要介绍的设计模式来解决——状态模式

一、模式定义

状态模式State Pattern

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

状态模式和策略模式的区别——意图是不同的

状态模式】随着时间流逝,当前状态在状态对象集合中游走改变,以反映出context内部的状态。客户对其基本不了解。它是针对具有很多条件判断的替代方案。
策略模式】客户通常主动指定context索要组合的策略对象是哪一个。它是继承之外的一种弹性替代方案。

二、模式类图

针对上面的介绍,我们来构造一下状态模式的类图,首先,创建状态接口State.java,接口里面包含了“插入硬币”、“退出硬币”、“扭转曲柄”和“发放糖果”这四个操作,那么具体的动作实现逻辑是与不同状态实现类一一对应的,也就是说,不同状态实现类负责各自的四个动作方法的具体实现。针对状态接口,我们创建4个实现类,分别是:糖果售卖状态类SoldState.java糖果售空状态类SoldOutState.java已经投放钱币状态类HasQuarterState.java没有投放钱币状态类NoQuarterState.java,那么当前处于哪个状态则由糖果售卖机类GumballMachine.java维护。具体类图请见下图所示:

三、代码实现

状态接口类State.java

public interface State {void insertQuarter(); // 投入硬币操作   void ejectQuarter(); // 退出硬币操作void turnCrank(); // 扭转曲柄操作void dispense(); // 发放糖果操作
}

糖果售卖状态类SoldState.java

public class SoldState implements State {private GumballMachine gumballMachine;public SoldState(GumballMachine gumballMachine) {this.gumballMachine = gumballMachine;}@Overridepublic void insertQuarter() {System.out.println("糖果正在出货中,请稍等。无须再次投入钱币!");}@Overridepublic void ejectQuarter() {System.out.println("糖果正在出货中,请稍等。不能退回钱币!");}@Overridepublic void turnCrank() {System.out.println("糖果正在出货中,请稍等。不需要再次扭转曲柄!");}@Overridepublic void dispense() {if (gumballMachine.getCount() > 0) {System.out.println("糖果正在出货中,请稍等!");gumballMachine.releaseBall();gumballMachine.setState(gumballMachine.getNoQuarterState()); // 状态流转} else {System.out.println("糖果库存不足,无法出货!");gumballMachine.setState(gumballMachine.getSoldOutState()); // 状态流转}}
}

糖果售空状态类SoldOutState.java

public class SoldOutState implements State {private GumballMachine gumballMachine;public SoldOutState(GumballMachine gumballMachine) {this.gumballMachine = gumballMachine;}@Overridepublic void insertQuarter() {System.out.println("糖果已经售罄。不能投入钱币");}@Overridepublic void ejectQuarter() {System.out.println("退回钱币成功!");}@Overridepublic void turnCrank() {System.out.println("糖果已经售罄。不能扭转曲柄!");}@Overridepublic void dispense() {System.out.println("糖果已经售罄。糖果无法出售!");}
}

已经投放钱币状态类HasQuarterState.java

public class HasQuarterState implements State {private GumballMachine gumballMachine;public HasQuarterState(GumballMachine gumballMachine) {this.gumballMachine = gumballMachine;}@Overridepublic void insertQuarter() {System.out.println("您已经投入钱币!无须再次投入钱币!");}@Overridepublic void ejectQuarter() {System.out.println("退款成功!");gumballMachine.setState(gumballMachine.getNoQuarterState()); // 状态流转}@Overridepublic void turnCrank() {System.out.println("正在出货中,请稍等");gumballMachine.setState(gumballMachine.getSoldState()); // 状态流转}@Overridepublic void dispense() {System.out.println("你还没有扭转曲柄,糖果不可以发放!");}
}

没有投放钱币状态类NoQuarterState.java

public class NoQuarterState implements State {private GumballMachine gumballMachine;public NoQuarterState(GumballMachine gumballMachine) {this.gumballMachine = gumballMachine;}@Overridepublic void insertQuarter() {System.out.println("投入钱币成功!");gumballMachine.setState(gumballMachine.getHasQuarterState()); // 状态流转}@Overridepublic void ejectQuarter() {System.out.println("你还没有投入钱币,不能退回钱币!");}@Overridepublic void turnCrank() {System.out.println("你还没有投入钱币,不能扭转曲柄!");}@Overridepublic void dispense() {System.out.println("你还没有投入钱币,糖果不可以发放!");}
}

糖果售卖机类GumballMachine.java

@Data
public class GumballMachine {private State noQuarterState;private State hasQuarterState;private State soldState;private State soldOutState;private State state = soldOutState; // 糖果机默认状态为售罄状态int count = 0; // 糖果库存量public GumballMachine(int numberGumballs) {noQuarterState = new NoQuarterState(this);hasQuarterState = new HasQuarterState(this);soldState = new SoldState(this);soldOutState = new SoldOutState(this);count = numberGumballs;if (numberGumballs > 0) {state = noQuarterState; // 如果采购了糖果球(numberGumballs>0),则糖果机的状态为未投币状态}}// 投入钱币public void insertQuarter() {state.insertQuarter();}// 退出钱币public void ejectQuarter() {state.ejectQuarter();}// 扭转曲柄public void turnCrank() {state.turnCrank();state.dispense();}// 减少库存public void releaseBall() {if (count > 0) {System.out.println("一个糖果球正在出库");--count;} else {System.out.println("库存不足,一个糖果球无法出库");}}// 设置状态void setState(State state) {this.state = state;}
}

状态模式测试类StateTest.java

public class StateTest {public static void main(String[] args) {System.out.println("-----向糖果机中放入1枚糖果-----");GumballMachine machine = new GumballMachine(1);System.out.println("-----第一次购买糖果-----");machine.insertQuarter();machine.ejectQuarter();machine.turnCrank();System.out.println("-----第二次购买糖果-----");machine.insertQuarter();machine.turnCrank();System.out.println("-----第三次购买糖果-----");machine.insertQuarter();machine.turnCrank();machine.ejectQuarter();}
}

今天的文章内容就这些了:

写作不易,笔者几个小时甚至数天完成的一篇文章,只愿换来您几秒钟的 点赞 & 分享 。

更多技术干货,欢迎大家关注公众号“爪哇缪斯” ~ \(^o^)/ ~ 「干货分享,每天更新」

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/139951.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

并查集题目

并查集是一种十分常用并且好用的数据结构 并查集可以动态维护若干个不重叠的集合,支持合并与查询操作,是一种树形的数据结构 并查集的基础应用 村村通 对于这道题我们只需要求连通块的数量,然后将这几个联通快看成点,我们可以知…

【华为云云耀云服务器L实例评测|云原生】自定制轻量化表单Docker快速部署云耀云服务器

🤵‍♂️ 个人主页: AI_magician 📡主页地址: 作者简介:CSDN内容合伙人,全栈领域优质创作者。 👨‍💻景愿:旨在于能和更多的热爱计算机的伙伴一起成长!!&…

笔记2.2:网络应用基本原理

一. 网络应用的体系结构 (1)客户机/服务器结构(Client-Server, C/S) (2)点对点结构(Peer-to-Peer,P2P) (3)混合结构(Hybrid&#x…

大数据学习技术栈及书籍推荐

作为一名开发人员,特别是后端开发人员,随着网络数据量的持续增长,拥有强大的大数据处理能力已经成为每个公司或产品(尤其是2C业务)的必备条件。以下是我在网络上搜集和自身研究的基础上,为您推荐的技术栈和…

【python】Seaborn画热力图,只显示第一行数字---seaborn与matplotlib版本问题

github上有这个讨论:Heatmap only has annotation text in the top row only Issue #3478 mwaskom/seaborn (github.com)翻译过来就是:热图仅在最上面一行有注释文本; 原因就是matplotlib 在2023年9月更新到了 3.8.0版本,改变了…

大数据Flink(八十三):SQL语法的DML:With、SELECT WHERE、SELECT DISTINCT 子句

文章目录 SQL语法的DML:With、SELECT & WHERE、SELECT DISTINCT 子句 一、DML:With 子句

c语言 static

1、静态局部变量在程序加载时初始化,静态局部变量的初始值写入到了data段: 如下代码test_symbol.c int f() {static int x 0;return x; }int g() {static int x 9;return x; }使用命令gcc -c test_symbol.c -o test_symbol 编译 使用命令 readelf -a …

Web ui自动化测试框架总结

【软件测试面试突击班】如何逼自己一周刷完软件测试八股文教程,刷完面试就稳了,你也可以当高薪软件测试工程师(自动化测试) 实施过了web系统的UI自动化,回顾梳理下,想到什么写什么,随时补充。 首…

数据分享|R语言逻辑回归、线性判别分析LDA、GAM、MARS、KNN、QDA、决策树、随机森林、SVM分类葡萄酒交叉验证ROC...

全文链接:http://tecdat.cn/?p27384 在本文中,数据包含有关葡萄牙“Vinho Verde”葡萄酒的信息(点击文末“阅读原文”获取完整代码数据)。 介绍 该数据集(查看文末了解数据获取方式)有1599个观测值和12个变量&#xf…

windows安装c环境

一. 下载安装mingw-w64 mingw-w64 解压后放到window环境变量路径 sysdm.cpl参看是否安装成功 二. 安装c idea Dev-Cpp下载及安装 新建文件 运行 编译(F9)、运行(F10)以及编译运行(F11) 参考 安装C…

Guava Cache介绍-面试用

一、Guava Cache简介 1、简介 Guava Cache是本地缓存,数据读写都在一个进程内,相对于分布式缓存redis,不需要网络传输的过程,访问速度很快,同时也受到 JVM 内存的制约,无法在数据量较多的场景下使用。 基…

图像处理之频域滤波DFT

摘要:傅里叶变换可以将任何满足相应数学条件的信号转换为不同系数的简单正弦和余弦函数的和。图像信号也是一种信号,只不过是二维离散信号,通过傅里叶变换对图像进行变换可以图像存空域转换为频域进行更多的处理。本文主要简要描述傅里叶变换…

Spring面试题11:什么是Spring的依赖注入

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:说一说Spring的依赖注入 依赖注入(Dependency Injection)是Spring框架的一个核心特性,它是指通过外部容器将对象的依赖关系注入到对象中,从而…

win10 关闭edge跳转IE浏览器

按下windows键,搜索控制面板 右上角输入IE 点击IE 高级中取消下红框选择即可

接口自动化测试之Requests模块详解

Python中,系统自带的urllib和urllib2都提供了功能强大的HTTP支持,但是API接口确实太难用了。Requests 作为更高一层的封装,在大部分情况下对得起它的slogan——HTTP for Humans。 让我们一起来看看 Requests 这个 HTTP库在我们接口自动化测试…

Spring面试题15:Spring支持几种bean的作用域?singleton、prototype、request的区别是什么?

该文章专注于面试,面试只要回答关键点即可,不需要对框架有非常深入的回答,如果你想应付面试,是足够了,抓住关键点 面试官:Spring支持几种bean的作用域? Spring支持以下几种Bean的作用域: Singleton(单例):这是Spring默认的作用域。使用@Scope(“singleton”)注解或…

web前端的float布局与flex布局

flex布局 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>flex</title><style>.container{width: 100%;height: 100px;background-color: aqua;display: flex;flex-direction: row;justify-content: space-ar…

使用 rtty 进行远程 Linux 维护和调试

rtty 是一个用于在终端上进行远程连接和数据传输的工具。它提供了一种简单的方式来与远程设备进行通信&#xff0c;使得在不同主机之间传输数据变得更加方便。 安装 rtty 是一个可执行程序&#xff0c;可以在 Linux、macOS 和 Windows 等平台上使用。 Linux/macOS 在终端中执…

web二级操作题

js和css的引入 在 HTML 中&#xff0c;你可以使用 <script> 和 <link> 标签来引入外部的 JavaScript 文件和 CSS 文件。 引入外部的 JavaScript 文件&#xff1a; <script src"path/to/script.js"></script>src 属性指定了 JavaScript 文…

Oracle for Windows安装和配置——Oracle for Windows数据库创建及测试

2.2. Oracle for Windows数据库创建及测试 2.2.1. 创建数据库 1&#xff09;启动数据库创建助手&#xff08;DBCA&#xff09; 进入%ORACLE_HOME%\bin\目录并找到“dbca”批处理程序&#xff0c;双击该程序。具体如图2.1.3-1所示。 图2.1.3-1 双击“%ORACLE_HOME%\bin\dbca”…