折腾Java设计模式之状态模式
原文地址 折腾Java设计模式之状态模式
状态模式
在状态模式(State Pattern)中,类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。通俗点就是一个对象在内部状态发生改变时改变它的行为。
介绍
意图 允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。
主要解决 对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。
何时使用 代码中包含大量与对象状态有关的条件语句。
如何解决 将各种具体的状态类抽象出来。
关键代码 通常命令模式的接口中只有一个方法。而状态模式的接口中有一个或者多个方法。而且,状态模式的实现类的方法,一般返回值,或者是改变实例变量的值。也就是说,状态模式一般和对象的状态有关。实现类的方法有不同的功能,覆盖接口中的方法。状态模式和命令模式一样,也可以用于消除 if...else 等条件选择语句。
UML图
主要角色
1)Context(环境类):环境类拥有各种不同状态的对象,作为外部使用的接口,负责调用状态类接口。
2)State(抽象状态):抽象状态既可以为抽象类,也可以直接定义成接口。主要用于定义状态抽象方法,具体实现由子类负责。
3)ConcreteState(具体状态类):具体状态类为抽象状态的实现者,不同的状态类对应这不同的状态,其内部实现也不相同。环境类中使用不同状态的对象时,能实现不同的处理逻辑
应用实例
1、打篮球的时候运动员可以有正常状态、不正常状态和超常状态。
2、曾侯乙编钟中,'钟是抽象接口','钟A'等是具体状态,'曾侯乙编钟'是具体环境(Context)。
优点
1、封装了转换规则。
2、枚举可能的状态,在枚举状态之前需要确定状态种类。
3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。
4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。
5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
缺点
1、状态模式的使用必然会增加系统类和对象的个数。
2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。
3、状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。
使用场景
行为随状态改变而改变的场景。
条件、分支语句的代替者。
状态模式和策略模式的对比
现在我们知道,状态模式和策略模式的结构是相似的,但它们的意图不同。让我们重温一下它们的主要不同之处:
- 策略模式封装了一组相关算法,它允许Client在运行时使用可互换的行为;状态模式帮助一个类在不同的状态显示不同的行为。
- 状态模式封装了对象的状态,而策略模式封装算法或策略。因为状态是跟对象密切相关的,它不能被重用;而通过从Context中分离出策略或算法,我们可以重用它们。
- 在状态模式中,每个状态通过持有Context的引用,来实现状态转移;但是每个策略都不持有Context的引用,它们只是被Context使用。
- 策略实现可以作为参数传递给使用它的对象,例如Collections.sort(),它的参数包含一个Comparator策略。另一方面,状态是Context对象自己的一部分,随着时间的推移,Context对象从一个状态转移到另一个状态。
- 虽然它们都符合OCP原则,策略模式也符合SRP原则(单一职责原则),因为每个策略都封装自己的算法,且不依赖其他策略。一个策略的改变,并不会导致其他策略的变化。
- 另一个理论上的不同:策略模式定义了对象“怎么做”的部分。例如,排序对象怎么对数据排序。状态模式定义了对象“是什么”和“什么时候做”的部分。例如,对象处于什么状态,什么时候处在某个特定的状态。
- 状态模式中很好的定义了状态转移的次序;而策略模式并无此需要:Client可以自由的选择任何策略。
- 一些常见的策略模式的例子是封装算法,例如排序算法,加密算法或者压缩算法。如果你看到你的代码需要使用不同类型的相关算法,那么考虑使用策略模式吧。而识别何时使用状态模式是很简单的:如果你需要管理状态和状态转移,但不想使用大量嵌套的条件语句,那么就是它了。
- 最后但最重要的一个不同之处是,策略的改变由Client完成;而状态的改变,由Context或状态自己。
项目实例
simple1包中主要是对风扇的开关状态进行转换,其实我们是把状态放在状态类中进行按照固定的逻辑转换,但是这种模式其实他不符合开闭原则,为什么了,因为一旦我们发生新增、修改或者删除状态的时候,就需要修改状态类中的状态转换。
public class Application {
public static void main(String[] args) {
Context context = new Context(new CloseLevelState());
context.right();
context.right();
context.right();
context.left();
context.right();
context.right();
}
}
抽象状态
public interface LevelState {
/**
* 左转
*
* @param context
*/
void left(Context context);
/**
* 右转
*
* @param context
*/
void right(Context context);
/**
* 当前档位
* @return
*/
String info();
}
具体档位状态,我只列了2个,其他的类似
@Slf4j
public class OneLevelState implements LevelState {
@Override
public void left(Context context) {
LevelState levelState = new CloseLevelState();
context.setLevelState(levelState);
log.info("风扇左转到{}", levelState.info());
}
@Override
public void right(Context context) {
LevelState levelState = new TwoLevelState();
context.setLevelState(levelState);
log.info("风扇右转到{}", levelState.info());
}
@Override
public String info() {
return "1档";
}
}
@Slf4j
public class CloseLevelState implements LevelState {
@Override
public void left(Context context) {
LevelState levelState = new ForeLevelState();
context.setLevelState(levelState);
log.info("风扇左转到{}", levelState.info());
}
@Override
public void right(Context context) {
LevelState levelState = new OneLevelState();
context.setLevelState(levelState);
log.info("风扇右转到{}", levelState.info());
}
@Override
public String info() {
return "0档";
}
}
真正的开关也就是上下文
@Data
@AllArgsConstructor
public class Context {
private LevelState levelState;
public void left() {
levelState.left(this);
}
public void right() {
levelState.right(this);
}
public String info() {
return levelState.info();
}
}
参考
欢迎关注
折腾Java设计模式之状态模式的更多相关文章
- 折腾Java设计模式之备忘录模式
原文地址:折腾Java设计模式之备忘录模式 备忘录模式 Without violating encapsulation, capture and externalize an object's int ...
- 折腾Java设计模式之访问者模式
博客原文地址:折腾Java设计模式之访问者模式 访问者模式 Represent an operation to be performed on the elements of an object st ...
- 折腾Java设计模式之命令模式
博客原文地址 折腾Java设计模式之命令模式 命令模式 wiki上的描述 Encapsulate a request as an object, thereby allowing for the pa ...
- 折腾Java设计模式之建造者模式
博文原址:折腾Java设计模式之建造者模式 建造者模式 Separate the construction of a complex object from its representation, a ...
- 折腾Java设计模式之模板方法模式
博客原文地址:折腾Java设计模式之模板方法模式 模板方法模式 Define the skeleton of an algorithm in an operation, deferring some ...
- JAVA设计模式--State(状态模式)
状态模式(State Pattern)是设计模式的一种,属于行为模式. 定义(源于Design Pattern):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 状态模式主要 ...
- JAVA设计模式:状态模式
声明:转载请说明来源:http://www.cnblogs.com/pony1223/p/7518226.html 一.引出状态模式 假设我们现在有一个糖果机项目,那么我们知道正常一般糖果机提供给用户 ...
- 折腾Java设计模式之迭代器模式
迭代器模式 Provide a way to access the elements of an aggregate object sequentially without exposing its ...
- Java设计模式之状态模式详解
(本文由言念小文原创,转载请注明出处) 在实际工作中经常遇到某个对象,处于不同的状态有不同行为逻辑.且状态之间可以相互迁移的业务场景,特别是在开发通信协议栈类软件中尤为多见.<设计模式之禅> ...
随机推荐
- c#位运算基本概念与计算过程
前言 一些非常基础的东西,在实际工作中没有用到.很少用到.一旦遇到,又不知所云.最近遇到一个问题,把一个int16(short) .两个bool变量整合成一个int32(int),当听到这个要求时,我 ...
- MySQL 复制 - 性能与扩展性的基石 2:部署及其配置
正所谓理论造航母,现实小帆船.单有理论,不动手实践,学到的知识犹如空中楼阁.接下来,我们一起来看下如何一步步进行 MySQL Replication 的配置. 为 MySQL 服务器配置复制非常简单. ...
- HTTP/2 简介
支撑现有 Web 服务的 HTTP 协议距离其发布时的 1997 年已经有些年月了,随后的 HTTP/1.1 版本发布自 1999 年.随着技术的进步和需求的进化,对于数据快速高效地传输,HTTP/1 ...
- 使用docker-compose 一键部署你的分布式调用链跟踪框架skywalking
一旦你的程序docker化之后,你会遇到各种问题,比如原来采用的本地记日志的方式就不再方便了,虽然你可以挂载到宿主机,但你使用 --scale 的话,会导致 记录日志异常,所以最好的方式还是要做日志中 ...
- android事件分发源码分析—笔记
昨天晚上从源码角度复习了一下android的事件分发机制,今天将笔记整理下放在网上.其实说复习,也是按着<android开发艺术探索>这本书作者的思路做的笔记. 目录 事件是如何从Acti ...
- Quartz.Net学习笔记
一.概述 Quartz.NET是一个强大.开源.轻量的作业调度框架,是 OpenSymphony 的 Quartz API 的.NET移植,用C#改写,可用于winform和asp.net应用中.它灵 ...
- Linux iptables 配置规则
Linux iptables 防火墙配置规则 前言:把网上我感觉不错iptables的访问规则都统一在这里,以后做参考. modprobe ipt_MASQUERADE modprobe ip_con ...
- ArcGIS注册数据库问题分析
本文是'猴妹'师妹授权给我来发表的,介绍都是师妹的研究成果,在此,非常感谢'猴妹'师妹. 用ArcGIS Server在发布地图服务时,注册数据库是很常见的,几年前就开始注册数据库,直到昨天,才有点顿 ...
- ABP项目依赖图,根据自已生在的Demo项目分析而得
根据自已生在的Demo项目分析而得 在线学习代码库:https://github.com/AtwindYu/ABPStudy
- 编程心法 之 敏捷开发(新架构)Agile Team Organization Squads, Chapters, Tribes and Guilds
Agile Team 参考 一般情况下,一个小组有以下功能分布: Squads 每个主要的功能的开发属于一个Squad,比如说QQ这个应用,可以分为QQ空间小组.QQ会员小组等等, 每一个Squad有 ...