else 策略模式去掉if_设计模式(三)——简单的状态模式代替if-else
博主将会针对Java面试题写一组文章,包括J2ee,SQL,主流Web框架,中间件等面试过程中面试官经常问的问题,欢迎大家关注。一起学习,一起成长。

前言
大多数开发人员现在还在使用if else的过程结构,曾看过jdon的banq大哥写的一篇文章,利用command,aop模式替代if else过程结构。当时还不太明白,这几天看了《重构》第一章的影片租赁案例,感触颇深。下面我来谈一谈为什么要用state pattern替代if else,替代if else有什么好处,以及给出详细代码怎么替代if else。
状态模式简介
意图:允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。
主要解决:对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。
何时使用:代码中包含大量与对象状态有关的条件语句。
如何解决:将各种具体的状态类抽象出来。
关键代码:通常命令模式的接口中只有一个方法。而状态模式的接口中有一个或者多个方法。而且,状态模式的实现类的方法,一般返回值,或者是改变实例变量的值。也就是说,状态模式一般和对象的状态有关。实现类的方法有不同的功能,覆盖接口中的方法。状态模式和命令模式一样,也可以用于消除 if...else 等条件选择语句。可与上一篇文章中的策略模式消除if-else作为对比。
需求
我们模仿商场根据不同日期来返回不同的价格,日期是不固定的,随时可能要增加,优惠力度也不是固定的。
传统if-else写法
/** * 根据不同的日期状态值获取不同的折后价格 */public class IfElseCode { private static int NORMAL = 1;//平时不打折 private static int CHRISTMAS = 2;//圣诞节打8折 private static int NEW_YEAR = 3;//新年打7折 /** * 获取价格 * @param dateCode 日期编码 * @param fullMoney 原价 * @return 折后的价格 */ public BigDecimal getCharge(int dateCode, BigDecimal fullMoney) throws BusinessException{ if(NORMAL == dateCode){ return fullMoney.multiply(BigDecimal.valueOf(1)); }else if(CHRISTMAS == dateCode){ return fullMoney.multiply(BigDecimal.valueOf(0.8)); }else if(NEW_YEAR == dateCode){ return fullMoney.multiply(BigDecimal.valueOf(0.7)); }else { throw new BusinessException("输入的日期编码有误!"); } }
缺点:如果有新增日期打折类型,就需要频繁的修改此处的代码,不符合开闭原则!
三、使用状态模式
3.1、定义状态接口
/** * 状态顶级接口 */public interface CashState { void doAction(Context context);//初始化方法 BigDecimal getCharge(BigDecimal fullPrice);//获取最终价格方法}
3.2、各个状态实现类
/** * 日常不打折的状态 */public class NormalState implements CashState { @Override public void doAction(Context context) { context.setState(this); } @Override public BigDecimal getCharge(BigDecimal fullPrice) { return fullPrice.multiply(BigDecimal.valueOf(1)); } public String toString(){ return "正常不打折"; }}
/** * 圣诞节的状态 */public class ChristmasState implements CashState { @Override public void doAction(Context context) { context.setState(this); } @Override public BigDecimal getCharge(BigDecimal fullPrice) { return fullPrice.multiply(BigDecimal.valueOf(0.8)); } public String toString(){ return "圣诞节打8折"; }}
/** * 新年的状态 */public class NewYearState implements CashState { @Override public void doAction(Context context) { context.setState(this); } @Override public BigDecimal getCharge(BigDecimal fullPrice) { return fullPrice.multiply(BigDecimal.valueOf(0.7)); } public String toString(){ return "新年打7折"; }}
3.3、定义上下文
/** * 上下文 */public class Context { private CashState state; public Context(){ state = null; } public void setState(CashState state){ this.state = state; } public CashState getState(){ return state; }}
3.4、调用示例
public class StatePatternMain { public static void main(String[] args) { BigDecimal fullPrice = BigDecimal.valueOf(10); Context context = new Context(); /**************日常不打折状态************/ CashState normalState = new NormalState(); normalState.doAction(context); System.out.println(context.getState().toString() +" ,最终价格="+ context.getState().getCharge(fullPrice)); /**************圣诞节的状态************/ CashState christmasState = new ChristmasState(); christmasState.doAction(context); System.out.println(context.getState().toString() +" ,最终价格="+ context.getState().getCharge(fullPrice)); /**************新年的状态************/ CashState newYearState = new NewYearState(); newYearState.doAction(context); System.out.println(context.getState().toString() +" ,最终价格="+ context.getState().getCharge(fullPrice)); }}
3.5、结果展示

总结
应用实例:
1、打篮球的时候运动员可以有正常状态、不正常状态和超常状态。
2、曾侯乙编钟中,'钟是抽象接口','钟A'等是具体状态,'曾侯乙编钟'是具体环境(Context)。优点:
1、封装了转换规则。
2、枚举可能的状态,在枚举状态之前需要确定状态种类。
3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
缺点:
1、状态模式的使用必然会增加系统类和对象的个数。
2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
3、状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。
使用场景:
1、行为随状态改变而改变的场景。
2、条件、分支语句的代替者。

相关文章:

bzoj 3598 [ Scoi 2014 ] 方伯伯的商场之旅 ——数位DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id3598 数位DP...东看西看:http://www.cnblogs.com/Artanis/p/3751644.html https://www.cnblogs.com/MashiroSky/p/6399095.html 好巧妙的思路啊!这样统计的东西就变得很简单了&#x…

OSI模型第四层传输层--TCP协议
1.传输层2个协议tcp和udp 2.tcp的可靠性(挂号信)。 面向链接的:类似寄挂号信,对方收到了并且能够确认。所以也是可靠的传输。 最大报文传输:两端可以协商传输报文大小。(协商一个报文的大小) 传输确认机制&…

evt参数是干啥用的_http连接池中非常关键的两个参数,到底是干啥用的?
作者简介:大厂一线资深开发。从crud开发到资深开发,再到研究员兼技术经理。《资深开发讲技术》 从一线实战中总结有故事,有背景的案例,希望带给大家一系列技术盛宴。求关注,欢迎技术交流。友情提醒,往期的文…

java 匿名类调用方法_java – 从匿名类调用新定义的方法
好问题.答案是否你不能直接调用date.someMethod();我们先来了解这是什么.Date date new Date() { ... };以上是延续Date类的匿名(没有名称)子类.当你看到代码,Runnable r new Runnable() {public void run() {}};这意味着您已经定义了正在实现(不扩展)Runnable接口的匿名(没有…

传图识字有次数限制吗_5岁娃识字3000?别羡慕!过早逼娃认字,后果很严重
在开始科普前,先祝大家“新年快乐”!2021年,科大大也会用更优质的育儿科普知识,回馈科粉们的支持和喜爱。话说回来,大家有什么新年flag呢?科大大发现,家长们比起给自己立flag,更愿意…

3des java 库_java 3DES 加密
public class DESCode {private String algorithm "DESede/CBC/PKCS7Padding";//加密方法/运算模式/填充模式private String charset "UTF-8";//编码private Cipher encCipher;//加密cipherprivate Cipher decCipher;//解密cipher…

[JSOI2008]魔兽地图
树上背包 题目传送门 首先,有没有哪位dalao 愿意告诉我为什么合成高级装备不需要附加金币,, 好吧,这个不重要 明确表示装备合成路线可以用一棵树来表示。一颗?傻乎乎的在下之前每次就只dp一棵树,不出意外的…

重大要素改变中的机会选择包括_财务人员专业胜任能力要素及框架
陈珏莹【本文导图】专业胜任能力要素框架的思维导图【概要】专业胜任能力要素构成了能力框架,因此,在构建各层次财务人才专业胜任能力框架之前要先界定能力要素。本文按照专业知识、职业技能和职业价值观三大部分简单介绍了各能力要素的概念。一个测评财…

tomcat部署 修改域名和访问域名时去掉项目名
修改域名和访问域名时去掉项目名 1、修改端口为80端口 因为80端口是为HTTP(HyperText Transport Protocol)即超文本传输协议开放的,浏览网页服务默认的端口号都是80,因此只需输入网址(或IP地址)即可。 打开tomcat安装目…

插入始终是1_40分!1分钟4次!大JB太硬了!
不得不说,巴爵士对赛事的预测还是稳如死狗昨儿他在节目中表示:热火赢不了雄鹿不过,话说出来可能就后悔了,表示如果爪机对血布能占上风,雄鹿还是有点麻烦。真的,巴爵士不再是我们印象中的那个自信的巴毒奶老…

一维卷积filter_从零开始学Pytorch(七)之卷积神经网络
卷积神经网络基础我们介绍卷积神经网络的卷积层和池化层,并解释填充、步幅、输入通道和输出通道的含义。import torch from torch.autograd import Variable aVariable(torch.FloatTensor([[2.,4.]]),requires_gradTrue) btorch.zeros(1,2) b[0,0]a[0,0]**2a[0,1] b…

nodejs配置nginx 以后链接mongodb数据库
服务器 :windows server2008 R2 反向代理 :nginx 1.15.1 for window 64位 数据库:mongodb 4 64位 使用框架express 首先下载nodejs 在官网或者中文网下载都可以 https://nodejs.org/zh-cn/ 然后将写好的项目打包成zip 上传 一定要带上 pac…

android切图尺寸_安卓设计尺寸规范
画布尺寸:如果想一稿适配ios,那就新建7201280 分辨率72,像素/英寸。如果单独设计安卓MD新规范的,那就新建10801920 分辨率72,像素/英寸。单位和度量 Units and measurementsdpi 屏幕宽度(或高度)像素 / 屏幕宽度(或高…

Vue.js使用前
下载安装 node,npm,git 安装cnpm 淘宝cnpm镜像https://npm.taobao.org/,-g表示进行全局安装 npm install -g cnpm --registryhttps://registry.npm.taobao.org # 全局安装 vue-cli$ npm install --global vue-cli# 创建一个基于 webpack 模板的新项目$ vue init web…

无法解析 list 中的方法 iterator_Python-list中的append()和extend()方法区别
一、append()和extend()方法都是用来添加数据到list末尾的,两者的区别:append()添加的时候会把添加的数据当成一个整体进行添加,允许添加任意类型的数据extend()添加的时候会把添加的数据迭代进行添加,只允许添加可迭代对象数据&a…

牛客网多校训练第一场 B - Symmetric Matrix(dp)
链接: https://www.nowcoder.com/acm/contest/139/B 题意: 求满足以下条件的n*n矩阵A的数量模m:A(i,j) ∈ {0,1,2}, 1≤i,j≤n.A(i,j) A(j,i), 1≤i,j≤n.A(i,1) A(i,2) ... A(i,n) 2, 1≤i≤n.A(1,1) A(2,2) ... A(n,n) 0.其中1≤n…

接口访问次数_系统运行缓慢,CPU 100%,Full GC次数过多,这一招帮你全搞定
处理过线上问题的同学基本上都会遇到系统突然运行缓慢,CPU 100%,以及Full GC次数过多的问题。当然,这些问题的最终导致的直观现象就是系统运行缓慢,并且有大量的报警。本文主要针对系统运行缓慢这一问题,提供该问题的排…

python3-pwntools教程_python的pwntools工具的日常使用
1.安装操作系统:ubuntu16.04环境准备:pythonpiplibssl-devlibffi-devpwntools安装:sudo apt-get install libffi-devsudo apt-get install libssl-devsudo apt-get install pythonsudo apt-get install python-pipsudo pip install pwntoolsp…

Spring MVC 返回json数据 报406错误 问题解决方案
将jackson jar包改为jackson-databind-2.5.0.jar jackson-core-2.5.0.jar jackson-annotations-2.5.0.jar(这个版本的jackson 测试返回json格式的数据百分百没问题,其他版本的不稳定,所以选用这个版本的Jackson)ResponseBody 然…

c# 读hex_c#十六进制到位转换(c# hex to bit conversion)
c#十六进制到位转换(c# hex to bit conversion)我试图将64位数字的十六进制表示(例如字符串"FFFFFFFFF" )转换为二进制表示( "11111..." )。我试过了string result Convert.ToString(Convert.ToUInt64(value, 16), 2);但是这会导致一个令人困惑…

pip install lxml失败原因
python3 是用 VC 14 编译的, python27 是 VC 9 编译的, 安装 python3 的包需要编译的也是要 VC 14 以上支持的. VC 14 (2015)下载地址: https://www.microsoft.com/zh-cn/download/confirmation.aspx?id48145&6B49FDFB-8E5B-4B07-BC31-1…

go语言服务器连接mysql_go语言原生连接数据库
go操作mysqldatabase/sql原生支持连接池,是并发安全的这个标准库没有具体实现,只是列出了一些需要第三方库实现的具体内容下载驱动go get -u github.com/go-sql-driver/mysql连接数据库package mainimport ("database/sql""fmt"_ &q…

2017《面向对象程序设计》寒假作业一
1、你有什么技能比大多人(超过70%以上)更好? 我看电影比一般人多一点点;我听英文歌比一般人多一点点;我有一把尤克里里和一个滑板。我有很多爱好,但都没能发展成我的特长,它们给我的生活增添了情…

gis中的加权求和工具在哪里_ArcGIS教程:加权总和的工作原理
使用加权总和工具可以对多个输入进行加权及组合,以创建整合式分析。它可以轻松地将多个栅格输入(代表多种因素)与组合权重或相对重要性相结合,在这一方面它与加权叠加工具很相似。这两种工具有两个主要区别:加权总和工具不能将重分类值重设为…

flask执行python程序_Flask app后如何执行代码(应用程序运行)开始
但我想使用一种方法,它还可以保存相机中的所有相框(我已经有功能了)。在问题是,一旦我启动了Flask应用程序,我最多只能存储在localhost中打开web页面时捕获的帧。我希望能够在应用程序运行时执行其他代码(保存图片),以便保存所有图…

异常处理与MiniDump详解(3) SEH(Structured Exception Handling)
write by 九天雁翎(JTianLing) -- blog.csdn.net/vagrxie 讨论新闻组及文件 一、 综述 SEH--Structured Exception Handling,是Windows操作系统使用的异常处理方式。 对于SEH,有点需要说明的是,SEH是属于操作系统的特性,不为特定…

电热水器技术性能指标
1、即热式和贮水式的选择 有使用安全、卫生、不受水压限制,随时可供热水,水温易调节等优点,在发达的西方国家已广泛地使用,即热式热水器体积小,不须预热,但功率大,通常在4-6kw以上࿰…

java相关网络协议无响应_java网络协议有哪些
上网的途径有很多,java是最普遍的,那么卑java网络协议有哪些?了解网络安全常识,首先就要了解计算机网络安全有哪些基本注意事项,下面佰佰安全网小编就带您认识一下吧。概念协议是指计算机通信网络中两台计算机之间进行通信所必须…

es日期format_elasticsearch存储日期格式字段
elasticsearch创建index之后,可以设置mapping,如果mapping中没有设置date的format,那么默认为两种格式:date_optional_time 此格式为ISO8601标准 示例:2018-08-31T14:56:18.00008:00epoch_millis 也就是时间戳 示例151…

arraylist 后往前遍历_面试官:谈谈常用的Arraylist和Linkedlist的区别
Arraylist:底层是基于动态数组,根据下表随机访问数组元素的效率高,向数组尾部添加元素的效率高;但是,删除数组中的数据以及向数组中间添加数据效率低,因为需要移动数组。例如最坏的情况是删除第一个数组元素…