Java设计模式-状态模式
状态模式: 允许一个对象在其内部状态改变时改变其行为, 其对象看起来像是改变了其类.
(图片来源: 设计模式:可复用面向对象软件的基础)
其目的是: 解决系统中复杂对象的状态流转以及不同状态下的行为封装问题.
模式实现
案例: 问题跟踪(Bug状态流转):
有过Kelude、Jira使用经验的同学都知道一个Bug由测试同学提出, 一直到被开发同学解决会经过一系列状态的流转:
新建(New) -> 打开(Open) -> 解决(Fixed) -> 关闭(Closed) …
且每种状态都会对应复杂业务的处理逻辑(如通知相应开发/测试人员、邮件/短信提醒、报表记录等等), 下面我们就以这个场景来讨论状态模式的实现:
状态模式-Bug流转:
State
抽象状态: 定义一个接口封装与 Context的一个特定状态 相关的行为:
/**
* @author jifang
* @since 16/8/28 下午6:06.
*/
public interface State {
void handle(Context context);
}
ConcreteState
具体状态: 每一个子类实现一个与 Context的某一个特定状态相关的具体行为 :
class NewState implements State {
static final NewState instance = new NewState();
// 单例 or 享元
public static State instance() {
return instance;
}
@Override
public void handle(Context context) {
if (context.getCurrent() == this) {
// 本状态下的核心业务处理
System.out.println("测试: 发现了Bug, 开发同学赶紧处理");
// 状态流转
context.setCurrent(OpenState.instance());
}
}
}
class OpenState implements State {
static final OpenState instance = new OpenState();
public static State instance() {
return instance;
}
@Override
public void handle(Context context) {
if (context.getCurrent() == this) {
System.out.println("开发: Bug已经看到, 正在处理");
context.setCurrent(FixedState.instance());
}
}
}
class FixedState implements State {
static final FixedState instance = new FixedState();
public static State instance() {
return instance;
}
@Override
public void handle(Context context) {
if (context.getCurrent() == this) {
System.out.println("开发: Bug已经修复, 测试同学看一下");
context.setCurrent(ClosedState.instance());
}
}
}
class ClosedState implements State {
static final ClosedState instance = new ClosedState();
public static State instance() {
return instance;
}
@Override
public void handle(Context context) {
if (context.getCurrent() == this) {
System.out.println("测试: Bug验证通过, 已关闭");
context.setCurrent(null);
}
}
}
Context
定义客户感兴趣的接口
维护一个ConcreteState子类实例 -当前状态.
public class Context {
private State current;
public Context(State current) {
this.current = current;
}
public State getCurrent() {
return current;
}
public void setCurrent(State current) {
this.current = current;
}
public void request() {
if (current != null) {
current.handle(this);
}
}
}
Client
public class Client {
@Test
public void client() {
Context context = new Context(NewState.instance());
context.request();
context.request();
context.request();
context.request();
context.request();
}
}
状态推动
前面介绍的状态流转需要由Client推动(Client调用Context的request()), 还有其他几种推动方式. 如State自动流转: 每个State处理结束, 自动进入下一状态的处理环节(在State内部调用Context的request()):
class NewState implements State {
@Override
public void handle(Context context) {
if (context.getCurrent() == this) {
System.out.println("测试: 发现了Bug, 开发同学赶紧处理");
context.setCurrent(new OpenState());
}
context.request();
}
}
另外还有一种基于表驱动的状态机实现, 实现细节参考 设计模式:可复用面向对象软件的基础 P204.
小结
将与特定状态相关的行为局部化, 并将不同状态的行为分隔开:
将特定的状态相关的行为都放入一个对象中: 由于所有与状态相关的代码都存在于某ConcreteState中, 所以通过定义新的子类可以很容易地增加新的状态和转换.
可以将状态转移逻辑分布到State之间, 将每一个状态转换和动作封装到一个类中, 就把着眼点从执行状态提高到整个对象的状态, 这将使代码结构化并使意图更加清晰,消除庞大的条件分支语句.
状态转换显式化:
当一个对象仅以内部数据值来定义当前状态时, 其状态仅表现为一些变量的赋值, 这不够明确. 为不同的状态引入独立的对象使得转换变得更加明确(类原子化).
场景:
当一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为;
一个操作中含有庞大的条件分支语句, 且这些分支依赖于该对象的状态, 这个状态通常用一个/多个枚举常量表示:
OA系统请求状态流转
银行系统资金状态流转
线程对象状态切换
TCP连接状态流转
State模式将每一个条件分支放入一个独立的类中. 这使得可以根据对象自身的情况将对象的状态作为一个对象, 这一对象可以不依赖于其他对象而独立变化.
- Centos下部署DRBD+NFS+Keepalived高可用环境记录
- jQuery方法position()与offset()区别
- 温故而知新:设计模式之桥接模式(Bridge)
- 温故而知新:设计模式之装饰模式(Decorator)
- 域名“宝贝”baby.cn以71万元价格结拍
- 温故而知新:设计模式之组合模式(Composite)
- ruby学习笔记(7)-闭包
- ruby学习笔记(6)-Array的使用
- centos7下部署iptables环境纪录(关闭默认的firewalle)
- ruby学习笔记(5)-模块module的运用
- linux系统root密码遗忘的情况下的解决办法
- ruby学习笔记(4)-动态修改类的属性
- 如果技术是一种生命
- ruby学习笔记(2)--类的基本使用
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- 浅析android studio3.5中使用recycleview的包
- Android自定义View实现拼图小游戏
- 解决android设备断电重启后WIFI不能自动重连的BUG(收藏)
- Android gradle配置抽取合并的操作步骤
- Android BottomNavigationBar底部导航的使用方法
- Android超清晰6.0权限申请AndPermission
- Android仿微信录制语音功能
- Android仿微信语音对讲录音功能
- flutter 屏幕尺寸适配和字体大小适配的实现
- flutter传递值到任意widget(当需要widget嵌套使用需要传递值的时候)
- android 9.0 launcher3 去掉抽屉式显示所有 app(代码详解)
- 图论-多源最短路径(Floyd算法)
- Android9.0 SystemUI 网络信号栏定制修改的流程解析
- 解决Android 10/Android Q手机在后台无法正常定位问题
- C语言CGI编程入门(一)