随遇而安-状态模式

随遇而安–状态模式


1. 状态模式介绍

状态模式中的行为是由状态来决定的,不同状态下有不同的行为,状态模式的行为是平行的,不可替换的;状态模式把对象的行为包装在不同的状态对象里,每一个状态对象都有一个共同的抽象状态基类。状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变。

2.状态模式的定义

当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变其类。

3.状态模式的使用场景

(1). 一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为

(2). 代码中含有大量有对象状态相关的条件语句,例如,一个操作中含有庞大的多分支语句(if-else或switch-case),且这些分支依赖于该对象的状态。

状态模式将每一个条件分支放入一个独立的类中,这使得你可以根据对象自身的状态来去除过多的,重复的if-else等分支语句。

4.状态模式的角色划分和UML类图

(1). UML类图 状态模式类图

(2). 角色划分

  • Context:环境类,定义客户感兴趣的接口,维护一个State子类的实例,这个实例定义了对象的当前状态。
  • State:抽象状态类或者状态接口,定义一个或者一组接口,表示该状态下的行为。
  • ConcreateStateA、ConcreateStateB:具体状态类,每一个具体的状态类实现抽象State中定义的接口,从而达到不同状态下的不同行为。

5.案列分析

下面我们就以电视机遥控器为例来演示下状态模式的实现。
需求分析:电视机有开机运行和关机停止运行两种状态,在开机状态下可以通过遥控器进行频道切换、调整音量等操作,但是此时重复开机按键无效;而在关机状态下,频道切换、调整音量、关机都操作都是无效的,只有按开机按钮才会生效,电视机的内部状态决定了遥控器的行为。

(1). 普通代码实现

/**
 * Created by zhangqing on 2018/3/4.
 * 电视机遥控器,含有开机,关机,下一频道、上一频道、调高音量、调低音量这个几个功能
 */
public class TvController {
    //开机状态
    private final static int POWER_ON = 1;
    //关机状态
    private final static int POWER_OFF = 2;
    private int mState = POWER_OFF;


    public void powerOn() {
        if (mState == POWER_OFF) {
            System.out.println("开机啦");
        }
        mState = POWER_ON;
    }


    public void powerOff() {
        if (mState == POWER_ON) {
            System.out.println("关机啦");
        }
        mState = POWER_OFF;
    }


    public void nextChannel() {
        if (mState == POWER_ON) {
            System.out.println("下一频道");
        } else {
            System.out.println("两个红灯提示,没有开机");
        }
    }


    public void preChannel() {
        if (mState == POWER_ON) {
            System.out.println("上一频道");
        } else {
            System.out.println("两个红灯提示,没有开机");
        }
    }


    public void turnUp() {
        if (mState == POWER_ON) {
            System.out.println("调高音量");
        } else {
            System.out.println("两个红灯提示,没有开机");
        }
    }


    public void turnDown() {
        if (mState == POWER_ON) {
            System.out.println("调低音量");
        } else {
            System.out.println("两个红灯提示,没有开机");
        }
    }
}

可以看到,在TvController类中,通过mState字段存储了电视机的状态,并且在各个操作中根据状态来判断是否应该执行,导致了每个功能中都有if-else,代码冗余、相对较为混乱,如果后期开发过程中状态变成5个,函数变成10个呢,会变得越来越难以维护,状态模式就是为解决这类问题而出现的,下面我们就来看下,将状态用对象来代替,将行为封装到类中使得在不同状态下有不同的实现,讲if-else从tvController中去掉,整个结构变得清晰起来,代码如下:

(2). 使用状态模式来实现代码

TvState.java

/**
 * Created by zhangqing on 2018/3/4.
 * 电视机状态接口,定义了电视操作的函数
 */
public interface TvState {
    public void nextChannel();


    public void prevChannel();


    public void turnUp();


    public void turnDown();
}

PowerOffState.java

/**
 * Created by zhangqing on 2018/3/4.
 * 关机状态,此时只有开机功能是有效的
 */


public class PowerOffState implements TvState {
    @Override
    public void nextChannel() {


    }


    @Override
    public void prevChannel() {


    }


    @Override
    public void turnUp() {


    }


    @Override
    public void turnDown() {


    }
}

PowerOnState.java

/**
 * Created by zhangqing on 2018/3/4.
 * 开机状态,此时再触发开机功能不做任何操作
 */


public class PowerOnState implements TvState {
    @Override
    public void nextChannel() {
        System.out.println("下一频道");
    }


    @Override
    public void prevChannel() {
        System.out.println("上一频道");
    }


    @Override
    public void turnUp() {
        System.out.println("调高音量");
    }


    @Override
    public void turnDown() {
        System.out.println("调低音量");
    }
}

PowerController.java

/**
 * Created by zhangqing on 2018/3/4.
 * 电源操作接口
 */


public interface PowerController {
    public void powerOn();


    public void powerOff();


}

TvController.java



/**
 * Created by zhangqing on 2018/3/4.
 * 电视遥控器,类似于经典状态模式中的Context
 */


public class TvController implements PowerController {


    TvState mTvState;


    public void setTvState(TvState tvState) {
        mTvState = tvState;
    }


    @Override
    public void powerOn() {
        setTvState(new PowerOnState());
        System.out.println("开机啦");
    }


    @Override
    public void powerOff() {
        setTvState(new PowerOffState());
        System.out.println("关机啦");
    }


    public void nextChannel() {
        mTvState.nextChannel();
    }


    public void preChannel() {
        mTvState.prevChannel();
    }


    public void turnUp() {
        mTvState.turnUp();
    }


    public void turnDown() {
        mTvState.turnDown();
    }
}

上述视线中,抽象了一个TvState接口,该接口中有操作电视的所有函数,该接口有开机状态(PowerOnState)和关机状态(PowerOffState)两个实现类,开机状态下只有开机功能是无效的,关机状态下只有开机功能是可用的,其它的功能都不会生效,电视机的内部状态影响了电视遥控器的行为。


总结:

状态模式将这不同状态下不同的行为封装到状态类中,在进行操作时,将这些功能转发给对应的状态下对象,不同的状态有不同的实现,通过多态的形式去掉了重复、杂乱的f-else语句。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值