敏捷软件开发(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大叔著。

时间: 2024-10-10 21:19:10

敏捷软件开发(1)--- STATE 模式的相关文章

敏捷软件开发 – ABSTRACT SERVER模式、ADAPTER模式和BRIDGE模式

设计运行在简易台灯中的软件.台灯由一个开关和一盏灯组成.可以询问开关是开着还是关着,也可以让灯打开或者关闭. 下面设计了一个简易的模型.Switch对象可以轮询实际开关的状态,并且可以发送相应的turnOn和turnOff消息给Light. 这个设计违反了两个设计原则:依赖倒置(DIP)和开放-封闭(OCP).对DIP的违反是明显的,Switch依赖了具体类Light.DIP告诉我们要优先依赖于抽象类.对OCP的违反虽然没有那么明显,但是更加切中要害.我们之所以不喜欢这个设计是因为它迫使我们在任

敏捷软件开发 – NULL OBJECT模式

考虑以下代码 Employee e = Db.GetEmployee("Bob"); if(e != null && e.IsTimeToPay(today)) { e.Pay(); } 大多数人曾经由于忘记对null进行检查而受挫.该管用手法虽然常见,但却是丑陋且易出错的. 通过让Db.GetEmployee抛出一个异常而不是返回null,可以减少出错的可能性.不过,try/catch块对比null的检查更加丑陋. 可以使用NULL OBJECT模式来解决这些问题.通

[书摘]《敏捷软件开发: 原则、模式与实践》第一部分:敏捷开发

面向对象设计的原则 单一职责 开放-封闭 Liskov替换原则 依赖倒置原则 接口隔离原则 重用发布等价原则 共同封闭原则 共同重用原则 无环依赖原则 稳定以来原则 稳定抽象原则 人的重要性 交付产品的关键因素是人,而不是过程.(敏捷 Agile) 人与人之间的交互式复杂的,并且其效果从来都是难以预期,但却是工作中最为重要的方面. ------ Tom DeMacro 和 Timothy Lister<人件> 有凝聚力的团队将具有最强大的软件开发力量. 敏捷软件开发宣言 我们一直在实践中探寻更

敏捷软件开发:原则、模式与实践(笔记)

一.敏捷软件开发宣言 1.个体和交互 > 过程与工具 a)人是获得成功最为重要的因素: b)合作.沟通以及交互能力要比单纯的编程能力更为重要: c)团队的构建要比环境的构建重要. 2.可以工作的软件 > 面面俱到的文档 a)文档应该短小并突出主题: b)在给新的团队成员传授知识方面,最好的两份文档是代码和团队: c)直到迫切需要并且意义重大时,才来编制文档. 3.客户合作 > 合同谈判 a)成功的项目需要有序.频繁的客户反馈. 4.响应变化 > 遵循计划 a)构建计划时,应该确保计

读书笔记-敏捷软件开发 原则,模式与实践

看了一下夹在书中的发票,2010年在当当网购买的. 断断续续的也看过几次,一直没有看完过. 这次试着写写读书笔记.看看能不能坚持住.

敏捷软件开发 – STATE模式

地铁旋转门 最直接的实现FSM策略的方式是使用嵌套switch/case语句. public enum State { LOCKED, UNLOCKED }; public enum Event { COIN, PASS }; public class TurnStile { private State state = State.LOCKED; private TurnstileController turnstileController; public TurnStile(Turnstile

敏捷软件开发 – FACADE模式和MEDIATOR模式

FACADE模式 Db类使得Application类不需要了解System.Data命名空间中的内部细节.它把System.Data的所有通用性和复杂性隐藏在一个非常简单且特定的接口后面. 像Db这样的FACADE类对System.Data的使用施加了许多规约.它知道如何初始化和关闭数据库连接.它知道如何将ProductData的成员变量转换成数据库字段,或反之.它知道如何去构建合适的查询和命令去操纵数据库.它对用户隐藏了所有的复杂性.在Application看来,System.Data是不存在

敏捷软件开发 – OCP 开放-封闭原则

软件实体(类.模块.函数等)应该是可以扩展的,但是不可修改的. 如果程序中的一处改动就会产生连锁反应,导致一系列相关模块的改动,那么设计就具有僵化性的臭味.OCP建议我们应该对系统进行重构,这样以后对系统再进行这样那样的改动时,就不会导致更多的修改.如果正确地应用OCP,那么以后再进行同样的改动时,就只需要添加新的代码,而不必改动已经正常运行的代码. OCP概述 遵循开放-封闭原则设计出的模块具有两个主要的特征.它们是: 对于扩展是开放的(open for extension).这意味着模块的行

敏捷软件开发 – SRP 单一职责原则

SRP:单一职责原则  一个类应该只有一个发生变化的原因. 为何把两个职责分离到单独的类中很重要呢?因为每一个职责都有变化的一个轴线.当需求变化时,该变化会反映为类的职责的变化.如果一个类承担了多于一个的职责,那么引起它变化的原因就会有多个. 如果一个类承担的职责过多,就等于把这些职责耦合在了一起.一个职责发生变化可能会削弱或抑制这个类完成其他职责的能力.这种耦合会导致脆弱的设计,当变化发生时,设计会遭受到意想不到的破坏. 有两个不同的应用程序使用Rectangle类.一个应用程序是有关计算几何

小议敏捷软件开发与传统软件工程

敏捷软件开发与传统软件工程 一.前言 随着社会和科技的不断发展,信息产业己经和人们的生活息息相关,成为不可或缺的一部分.软件工程作为信息产业的核心部分发生了翻天覆地的变化.传统的软件工程思想己经越来越不适应快速变化的信息社会,为此一种新软件工程思想-----敏捷软件开发进入了我们的视野. 二.软件工程 (一)概述 Software engineering is the application of engineering to the design, development, implement