敏捷软件开发(1)--- STATE 模式
如果状态在运行过程中,不停的切换和改变,我们怎么办?
状态的迁移是我们生活和工程中非常普遍的一个概念。于是在数学上有一种理论来分析和解决这个问题。
有限状态机理论是一个非常成熟的理论,所有动作和流程的迁移可以归结为状态的迁移。
这个理论的前提是:
状态的数目是确定的,或者说是有限的。
状态的迁移方向是固定的,也就是有向的。
状态存储关于过去的信息,就是说:它反映从系统开始到现在时刻的输入变化。转移指示状态变更,并且用必须满足来确使转移发生的条件来描述它。动作是在给定时刻要进行的活动的描述。有多种类型的动作:
进入动作(entry action):在进入状态时进行
退出动作:在退出状态时进行
输入动作:依赖于当前状态和输入条件进行
转移动作:在进行特定转移时进行
下面我们将按照一个地铁轧机的操作来讲解有线状态机理论。

地铁轧机的整体状态图如上。基本就是开和关2种行为。
关于FSM,可以有3种实现方式。
1.switch case方式
package com.joyfulmath.state.switchcase; /**
* @author deman.lu
* @version on 2016-05-18 09:43
*/
public class Turnstile { //status
public static final int LOCKED = 0;
public static final int UNLOCKED = 1; //events
public static final int COIN = 0;
public static final int PASS = 1; int state = LOCKED; private TurnstileController turnstileController; public Turnstile(TurnstileController turnstileController) {
this.turnstileController = turnstileController;
} public void enent(int event)
{
switch (state)
{
case LOCKED:
switch (event)
{
case COIN:
state = UNLOCKED;
turnstileController.unlock();
break;
case PASS:
turnstileController.alarm();
break;
}
break;
case UNLOCKED:
switch (event)
{
case COIN:
turnstileController.thankYou();
break;
case PASS:
state = LOCKED;
turnstileController.lock();
break;
}
break;
}
}
}
/**
* @author deman.lu
* @version on 2016-05-18 09:47
*/
public interface TurnstileController {
void lock();
void unlock();
void alarm();
void thankYou();
}
状态的迁移在switch-case语句里面进行。当前是2种状态 & 2种触发条件。
switch-case 就是2*2 的结果。可以相见,如果情况复杂化,switch-case将呈现爆炸式增长。
2.解释迁移表
该方法在很早以前的C语言中很常见,我个人也经历过这样的代码,并且维护过一段时间。
说句实话,这个东西有点C语言实现面向对象的思想。当然和Java语言没法比较。
package com.joyfulmath.state.switchcase; import java.util.ArrayList;
import java.util.List; /**
* @author deman.lu
* @version on 2016-05-18 10:05
*/
public class TurnStyle {
int state = Turnstile.LOCKED;
TurnstileController turnstileController;
List<Transition> mTransitions = new ArrayList<>();
public TurnStyle(final TurnstileController turnstileController) {
this.turnstileController = turnstileController;
addTransition(Turnstile.LOCKED, Turnstile.COIN, Turnstile.UNLOCKED, new Runnable() {
@Override
public void run() {
turnstileController.unlock();
}
});
} private void addTransition(int state, int event, int nextstate, Runnable runnable) {
Transition transition = new Transition();
transition.currentState = state;
transition.event = event;
transition.nextState = nextstate;
transition.runnable = runnable;
mTransitions.add(transition);
} public void event(int event)
{
for(Transition transition:mTransitions)
{
if(transition.currentState == state && event == transition.event)
{
state = transition.nextState;
transition.runnable.run();
}
}
}
}
迁移表的维护,有些困难。一点大量状态 & 事件存在,该表将非常复杂。
3.state 模式
好在软件开发中,还有设计模式这个礼物。使用state模式,是目前实现FSM来说,非常适合的一种方式。
package com.joyfulmath.state.statemode; /**
* @author deman.lu
* @version on 2016-05-18 10:43
*/
public interface ITurnstitleState {
void coin(TurnsStatus t);
void pass(TurnsStatus t);
}
这是event事件。
状态的实现:
package com.joyfulmath.state.statemode; /**
* @author deman.lu
* @version on 2016-05-18 10:52
*/
public class LockedStatus implements ITurnstitleState {
@Override
public void coin(TurnsStatus t) {
t.setUnLock();
t.unlock();
} @Override
public void pass(TurnsStatus t) {
t.alarm();
}
}
package com.joyfulmath.state.statemode; /**
* @author deman.lu
* @version on 2016-05-18 10:53
*/
public class UnLockedStatus implements ITurnstitleState {
@Override
public void coin(TurnsStatus t) {
t.thankyou();
} @Override
public void pass(TurnsStatus t) {
t.setLock();
t.lock();
}
}
TurnsStatus是驱动状态迁移的关键。在有些介绍状态模式的书里面,这个类一般定义为context
package com.joyfulmath.state.statemode; import com.joyfulmath.state.switchcase.TurnstileController; /**
* @author deman.lu
* @version on 2016-05-18 10:52
*/
public class TurnsStatus {
private static ITurnstitleState lockedStatus = new LockedStatus();
private static ITurnstitleState unlockedStatus = new UnLockedStatus(); private TurnstileController controller;
private ITurnstitleState state = lockedStatus;
public TurnsStatus(TurnstileController controller) {
this.controller = controller;
} public void coin()
{
state.coin(this);
} public void pass()
{
state.pass(this);
} public void setLock()
{
state = lockedStatus;
} public void setUnLock()
{
state = unlockedStatus;
} void thankyou()
{
controller.thankYou();
} void alarm()
{
controller.alarm();
} void lock()
{
controller.lock();
} void unlock()
{
controller.unlock();
}
}
其中coin & pass 方法是供外部类进行调用的,而
void unlock()
{
controller.unlock();
}
这些方法是给state做处理的。
状态模式彻底的分离了状态机的逻辑和动作。
动作在Context类中实现,而逻辑在各个state中实现。
从个人经验来讲,状态模式适合状态会反复切换的场景。
参考:
《敏捷软件开发》 BOb大叔著。
敏捷软件开发(1)--- STATE 模式的更多相关文章
- 敏捷软件开发vs传统软件开发
摘要 本文介绍了传统软件开发(着重介绍了传统软件开发中常用的瀑布模型)和敏捷软件开发,以及敏捷开发和传统开发的对比. 一.传统软件开发 比较常用的几种传统软件开发方法:瀑布式开发.迭代式开发.螺旋开发 ...
- 敏捷软件开发(4)--- TEMPLATE METHOD & STRATEGY 模式
1.TEMPLATE METHOD 泛型,也就是这个模式,是可以基于泛型的. 我们往往会有一些算法,比如排序算法.它的算法部分,我可以把它放在一个基类里面,这样具体类型的比较可以放在子类里面. 看如下 ...
- 敏捷软件开发(3)---COMMAND 模式 & Active Object 模式
COMMAND 模式 command模式非常简单,简单到你无法想象的地方. public interface Command { void execute(); } 这就是一个command模式的样子 ...
- 敏捷软件开发:原则、模式与实践——第14章 使用UML
第14章 使用UML 在探索UML的细节之前,我们应该先讲讲何时以及为何使用它.UML的误用和滥用已经对软件项目造成了太多的危害. 14.1 为什么建模 建模就是为了弄清楚某些东西是否可行.当模型比要 ...
- 敏捷软件开发:原则、模式与实践——第12章 ISP:接口隔离原则
第12章 ISP:接口隔离原则 不应该强迫客户程序依赖并未使用的方法. 这个原则用来处理“胖”接口所存在的缺点.如果类的接口不是内敛的,就表示该类具有“胖”接口.换句话说,类的“胖”接口可以分解成多组 ...
- 敏捷软件开发:原则、模式与实践——第10章 LSP:Liskov替换原则
第10章 LSP:Liskov替换原则 Liskov替换原则:子类型(subtype)必须能够替换掉它们的基类型(base type). 10.1 违反LSP的情形 10.1.1 简单例子 对L ...
- 敏捷软件开发:原则、模式与实践——第8章 SRP:单一职责原则
第8章 SRP:单一职责原则 一个类应该只有一个发生变化的原因. 8.1 定义职责 在SRP中我们把职责定义为变化的原因.如果你想到多于一个的动机去改变一个类,那么这个类就具有多于一个的职责.同时,我 ...
- 【Scrum】-NO.40.EBook.1.Scrum.1.001-【敏捷软件开发:原则、模式与实践】- Scrum
1.0.0 Summary Tittle:[Scrum]-NO.40.EBook.1.Scrum.1.001-[敏捷软件开发:原则.模式与实践]- Scrum Style:DesignPattern ...
- 敏捷软件开发:原则、模式与实践——第13章 写给C#程序员的UML概述
第13章 写给C#程序员的UML概述 UML包含3类主要的图示.静态图(static diagram)描述了类.对象.数据结构以及它们之间的关系,藉此表现出了软件元素间那些不变的逻辑结构.动态图(dy ...
随机推荐
- multi-CPU, multi-core and hyper-thread--转
原文地址:http://stackoverflow.com/questions/680684/multi-cpu-multi-core-and-hyper-thread Multi-CPU was t ...
- 清除linux缓存命令
命令 #sync #echo 3 > /proc/sys/vm/drop_caches 查看内存情况: # more /proc/meminfo Kernels 2.6.16 and newer ...
- Node.js Web 开发框架大全《静态文件服务器篇》
这篇文章与大家分享优秀的 Node.js 静态服务器模块.Node 是一个服务器端 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用程序,编写能 ...
- [git]使用GPG签名你的commit
概述 GPG是一种加密算法,现在github支持commit使用GPG加密,从而保证提交的commit在传输的过程中没有被篡改. 一.生成GPG密钥 什么是GPG:阮一峰的GPG教程 安装GPG:br ...
- 初涉SQL Server性能问题(4/4):列出最耗资源的会话
在上3篇文章里,我们讨论了列出反映服务器当前状态的不同查询. 初涉SQL Server性能问题(1/4):服务器概况 初涉SQL Server性能问题(2/4):列出等待资源的会话 初涉SQL Ser ...
- python之异常处理
异常处理是高级编程语言必备的一个功能模块. 一.异常基础 在编程过程中为了增加友好性.容错性和健壮性,在程序出现bug时一般不会将错误信息显示给用户,而是现实一个提示的页面,通俗来说就是不让用户看见大 ...
- ADO.NET学习系列(四)---窗体版的登录小程序
1.需求分析:做一个登录的小程序,基于Winform的窗体小程序.基本要求:登录成功:弹框显示登录成功,登录失败就弹框显示失败. 扩展功能:登录次数超过3次,就”锁定“用户,提示登录错误次数过多,不能 ...
- 克隆复制可使用原型( Prototype)设计模式
今天有学习设计模式的原型(Prototype)<设计模式--原型(Prototype)模式>http://www.cnblogs.com/insus/p/4152773.html .为了加 ...
- Winform开发框架之权限管理系统改进的经验总结(3)-系统登录黑白名单的实现
在一般的权限系统里面,可能经常会看到系统的黑名单或者白名单的拦截功能.在一般权限系统里面,常见的黑名单就是禁止用户在某些IP上登录系统,白名单就是允许用户只在某些IP上登录系统.本随笔主要介绍在我的权 ...
- 利用Aspose.Cell控件导入Excel非强类型的数据
导入Excel的操作是非常常见的操作,可以使用Aspose.Cell.APOI.MyXls.OLEDB.Excel VBA等操作Excel文件,从而实现数据的导入,在导入数据的时候,如果是强类型的数据 ...