Java设计模式之状态模式
作者:tianClassmate 发布时间:2022-05-08 07:24:25
实际开发中订单往往都包含着订单状态,用户每进行一次操作都要切换对应的状态,而每次切换判断当前的状态是必须的,就不可避免的引入一系列判断语句,为了让代码更加清晰直观,我们引入今天的主角——状态模式。
一、概念理解
假设订单状态有,下单、发货、确认收货,如果用户确认收货,在常规编程中就要判断当前用户的状态,然后再修改状态,如果这种情况下使用状态模式。
将各个状态都抽象成一个状态类,比如下单状态类、发货状态类、确认收货类,在状态类中处理相应的逻辑和控制下一个状态,在定义一个环境类,定义初始状态,并控制切换状态。
在状态模式中应该包含着三个角色:
环境类(Context)角色:也称为上下文,它定义了客户端需要的接口,内部维护一个当前状态,这个类持有State接口,负责保持并切换当前的状态。
抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为。
具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。
以下为状态模式的类图,看起来是很直观的,理解起来也简单,我们需要说明的是状态模式的类图和策略模式的类图长的一样,但写起来状态模式比策略模式要难。
我们要注意这段话,在状态模式中,类的行为是基于它的状态改变的,状态之间的切换,在状态A执行完毕后自己控制状态指向状态B,状态模式是不停的切换状态执行。这也是状态模式和策略模式不一样的地方。
另外在状态模式中,状态A到B是由自己控制的,而不是由客户端来控制,这是状态模式和策略模式最显著的特征。
我们基于订单状态案例实现demo。
二、案例实现
抽象状态:
定义统一的状态切换方法
/**
* 抽象状态
* @author tcy
* @Date 20-09-2022
*/
public abstract class OrderStateAbstract {
protected Context context;
public void setContext(Context context) {
this.context = context;
}
/**
* 状态切换
*/
public abstract void handle();
}
具体状态-订单付款:
实现状态接口,处理相应的逻辑,并定义下一个状态
/**
* 订单付款
* @author tcy
* @Date 21-09-2022
*/
public class OrderStatePay extends OrderStateAbstract {
@Override
public void handle() {
System.out.println("订单已支付,执行下个状态...");
context.changeState(new OrderStateOut());
}
}
具体状态-订单发货
/**
* 订单发货
* @author tcy
* @Date 21-09-2022
*/
public class OrderStateOut extends OrderStateAbstract {
@Override
public void handle() {
System.out.println("订单已经发货,开始下一状态...");
context.changeState(new OrderStateSubmit());
}
}
具体状态-订单确认收货
/**
* 订单提交
* @author tcy
* @Date 21-09-2022
*/
public class OrderStateSubmit extends OrderStateAbstract {
@Override
public void handle() {
System.out.println("订单已经确认收货...");
}
}
环境类:
持有最新状态,并调用具体的状态切换方法
/**
* 环境类
* @author tcy
* @Date 20-09-2022
*/
public class Context {
private OrderStateAbstract state;
//定义环境类的初始状态
public Context() {
this.state = new OrderStatePay();
state.setContext(this);
}
//状态切换
public void changeState(OrderStateAbstract state) {
this.state = state;
this.state.setContext(this);
}
/**
* 审批通过请求
*/
public void request() {
this.state.handle();
}
}
客户端调用:
/**
* @author tcy
* @Date 20-09-2022
*/
public class Client {
public static void main(String[] args) {
//创建环境
Context context = new Context();
//订单付款
context.request();
//订单发货
context.request();
//订单付款
context.request();
}
}
状态模式客户端调用比较简单,由状态内部类进行状态切换。
三、总结
很多博客都将策略模式的案例代码当做状态模式来讲解,这是不正确的,读者可以参考策略模式两篇做对比学习,认真体会他们之间的区别。
在实际开发中,当控制一个对象状态转换的条件表达式过于复杂时,就可以使用状态模式把相关“判断逻辑”提取出来,用各个不同的类进行表示。
系统处于哪种情况,直接使用相应的状态类对象进行处理,这样能把原来复杂的逻辑判断简单化,消除了 if-else、switch-case 等冗余语句,代码更有层次性,并且具备良好的扩展力。
比如审批流程,我们案例也仅仅是用于订单流程做例子,在实际开发中并不会使用这种方式处理订单,因为订单的处理逻辑实际上并不是那么复杂,引入状态模式反而增加了更多的类,造成系统更加的复杂,这也是设计模式最显著的缺点。
来源:https://www.cnblogs.com/tianClassmate/p/16733554.html


猜你喜欢
- 开门见山 项目运行的环境里面已经有该项目的所有代码依赖,所以项目的代码只要将自己的代码打入进去就能提交到环境中运行了。但是不好的地方就是项
- 经常要检测某些IP地址范围段的计算机是否在线。有很多的方法,比如进入到网关的交换机上去查询、使用现成的工具或者编写一个简单的DOS脚本等等,
- 腾讯TBS浏览器服务我们都知道,在Android开发中,经常会用到Webview,而且WebView是出了名的坑的,各种bug。这时候腾讯老
- 本文实例为大家分享了Java代码对HDFS进行增删改查操作的具体代码,供大家参考,具体内容如下import java.io.File;imp
- 在项目开发中,我们经常会遇到表中的字段名和表对应实体类的属性名称不一定都是完全相同的情况,下面小编给大家演示一下这种情况下的如何解决字段名与
- 前几天在“Android绘图之渐隐动画”一文中通过画线实现了渐隐动画,但里面有个问题,画笔较粗(大于1)时线段之间会有裂隙,我又改进了一下。
- 前言CMake是一个跨平台的安装编译工具,可以用简单的语句来描述所有平台的安装(编译过程)。CMake可以说已经成为大部分C++开源项目标配
- 本文实例讲述了C#编程实现QQ界面的方法。分享给大家供大家参考,具体如下:步骤:1.新建一个页面,假如说叫VerticalMenu2.把ht
- SpringBoot Web依赖本文,主要记录如何切换Springboot内部 web依赖。在使用SpringBoot时,首先引人注意的便是
- Java时间格式转换大全import java.text.*;import java.util.Calendar;public class
- 安装hbase首先下载hbase的最新稳定版本 http://www.apache.org/dyn/closer.cgi/hbas
- 本文实例讲述了Spring实战之@Autowire注解用法。分享给大家供大家参考,具体如下:一 配置<?xml version=&qu
- 本文实例实现C#以一个收银付费的小程序演示switch case语法如何使用,读入用户选择,把用户的选择赋值给变量n,再根据用户的输入提示付
- 在本文中,我将向你展示c#编程的5个最佳实践。我从日常编程经验中学到了这些实践。我在release模式下测试了所有的代码,并在开发环境稳定后
- 这个例子只是简单实现了如何使用 Socket 类实现面向连接的通信。注意:此例子的目的只是为了说明用套接字写程序的大概思路,而不是实际项目中
- XAML:<Grid>  
- 一、跨域认证的问题互联网服务离不开用户认证。一般流程是下面这样。1、用户向服务器发送用户名和密码。2、服务器验证通过后,在当前对话(sess
- 前言容器是用于存放数据的载体。容器分为数组、集合。 Kotlin 作为一门全新的语言,肯定还是要有自己的容器类,不然哪天 Java 跟 Ko
- 本文实例为大家分享了Android绝对布局AbsoluteLayout的具体代码,供大家参考,具体内容如下1>AbsoluteLayo
- 我们都知道, Android EditText输入框,并没有监听用户输入完成的功能,需要我们自己实现。 下面是实现的方法,仅供参考:Edit