设计模式 - 状态模式(State)

State模式允许一个对象在其内部状态改变时改变它的行为。当一个
对象收到其他对象的请求时, 它根据自身的当前状态作出不同的反应。
• 一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为;同时对象的行为引起对象的状态的改变。
• 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常, 有多个操作包含这一相同的条件结构。State模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。

通过 state模式去除复杂的状态改变条件语句。

类图:
这里写图片描述

案例:地铁闸机状态机

  • 若状态机在lock状态收到一个coin事件,状态改变成unlocked状态并执行unlock动作;
  • 若状态机在unlock状态再收到一个coin事件,状态不变显示”thank you”;
  • 若状态机在unlock状态收到一个pass事件,状态改变成locked状态并执行lock动作;
  • 若状态机在lock状态收到一个pass事件,状态不变并报警。

这里写图片描述

Step 1: 没有使用State模式,Turnstile对象负责接收事件,TurnstileController负责执行动作。

public class Turnstile {
    //states
    public static final int LOCKED   = 0;
    public static final int UNLOCKED = 1;

    private TurnstileController controller;
    private int state = LOCKED;

    public Turnstile(TurnstileController controller) {
        this.controller = controller;
    }
    public void coin() { //coin event
        if(state == LOCKED) {//状态改变条件语句
            state = UNLOCKED;
            unlock();
        } else {
            thankyou();
        }
    }
    public void pass() { //pass event
        if(state == UNLOCKED) {//状态改变条件语句
            state = LOCKED;
            lock();
        } else {
            alarm();
        }   
    }   
    public void unlock() {
        controller.unlock();
    }
    public void lock() {
        controller.lock();
    }   
    public void alarm() {
        controller.alarm();
    }
    public void thankyou() {
        controller.thankyou();
    }
    public boolean isLocked() {
        return state == LOCKED;
    }
    public void setLocked() {
        state = LOCKED;
    }
    public boolean isUnlocked() {
        return state == UNLOCKED;
    }
    public void setUnlocked() {
        state = UNLOCKED;
    }   
}
public class TurnstileController {
    public void unlock() {
        System.out.println("unlocked turnstile");
    }
    public void thankyou() {
        System.out.println("thank you");
    }
    public void lock() {
        System.out.println("Locked turnstile");
    }
    public void alarm () {
        System.out.println("Can not pass as it is locked");
    }   
}

测试代码:

public class TurnstileTest {
    @Test
    public void testTurntileTest() {
        TurnstileController controller = new TurnstileController();
        Turnstile turntile = new Turnstile(controller);
        assertTrue(turntile.isLocked());
        turntile.coin();
        assertTrue(turntile.isUnlocked());

        turntile.coin();
        assertTrue(turntile.isUnlocked());

        turntile.pass();
        assertTrue(turntile.isLocked());

        turntile.pass();
        assertTrue(turntile.isLocked());

    }
}

Step 2: 使用State模式重构去除这些状态改变条件语句。
可以识别出coin()和pass()方法里有状态改变条件语句,定义一个State的接口或抽象超类,将这些方法复制到State的接口或抽象超类 (将上下文类Turnstile传入State中的方法,State的实现类可以调用上下文的方法):

public interface TurnstileState {
    public void coin(Turnstile turnstile);
    public void pass(Turnstile turnstile);
}

定义实现TurnstileState接口的两个State类:

public class LockedTurntileState implements TurnstileState {
    public void coin(Turnstile turnstile) { //coin event
        turnstile.setUnlocked();
        turnstile.unlock();
    }
    public void pass(Turnstile turnstile) { //pass event
        turnstile.alarm();
    }   
}
public class UnlockedTurnstileState implements TurnstileState {
    public void coin(Turnstile turnstile) {
        turnstile.thankyou();
    }
    public void pass(Turnstile turnstile) {
        turnstile.setLocked();
        turnstile.lock();
    }
}

Step 3: 重构Turnstile,Turnstile称为上下文(context),上下文对象将状态相关的行为委托到状态对象上;上下文对象有一个初始的状态对象。
1) 将状态类型码换成 状态对象
2) coin() 和 pass() 委托给当前的状态对象

public class Turnstile {
    //replace state types with state objects
    public static final TurnstileState lockedState = new LockedTurntileState();
    public static final TurnstileState unlockedState = new UnlockedTurnstileState();

    private TurnstileController controller;
    private TurnstileState state = lockedState;//初始的状态对象

    public Turnstile(TurnstileController controller) {
        this.controller = controller;
    }
    public void coin() { 
        state.coin(this); //delegate state object
    }
    public void pass() { 
        state.pass(this); delegate state object 
    }   
    public void unlock() {
        controller.unlock();
    }
    public void lock() {
        controller.lock();
    }   
    public void alarm() {
        controller.alarm();
    }
    public void thankyou() {
        controller.thankyou();
    }
    public boolean isLocked() {
        return state == lockedState;
    }
    public void setLocked() {
        state = lockedState;
    }
    public boolean isUnlocked() {
        return state == unlockedState;
    }
    public void setUnlocked() {
        state = unlockedState;
    }   
}

通过将Context类中的State变量封装成状态类,状态相关的行为委托到状态对象上,从而去除Context中状态相关的方法中复杂状态改变条件语句。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值