(8)状态模式

定义

当一个对象的内在状态改变是允许改变其行为,这个对象看起来像是改变了其类。关键点在于不同的状态对于同一行为有不同的表现(类似多态:同一个行为具有多个不同表现形式或形态的能力。)

跟策略模式特别像,区别在于策略模式里面的不同策略目的,本质完全不一样,可以彼此独立,可以相互替换(类似数学概率里的互斥事件)。而状态模式不一样,它的行为是平行的,不可替换的(类似对立事件)


使用场景

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

  • 代码中包含大量与对象“状态”(例如冰箱开机与关机)相关的条件语句if-else

  • 比如Android中的Wifi功能

UML图

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

实例


优点

  • 将所有与一个特定的状态相关的行为都放入一个状态对象中,它提供了一个状态方法来组织与特定状态相关的代码,将繁琐的状态判断装换成结构清晰的状态类族,在避免膨胀的同时也保证了可扩展性和可维护性

缺点

  • 状态模式的使用必然会增加系统类和对象的个数

例子

用电视机作为例子,电视机升高音量降低音量的功能,而已打开电源的电视机和已关闭的电视机是电磁炉的2种状态(不是开的就是关的)

  1. 假如未用状态模式前,应该是用的if-else语句判断状态然后执行方法,具体如下
/** 普通情况,if-else判断的
 * Created by Niwa on 2017/8/20.
 */
public class TvControllerNomal {
    /**
     * 关机状态标志
     */
    private final static int POWER_OFF = 2;
    /**
     * 开机状态标志
     */
    private final static int POWER_ON = 1;
    /**
     * 默认状态
     */
    private int mState = POWER_OFF;

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

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

    public void nextChannel() {
        if (mState == POWER_ON) {
            System.out.println("下一频道");
        }
    }
    public void preChannel() {
        if (mState == POWER_ON) {
            System.out.println("上一频道");
        }
    }
    public void turnUp() {
        if (mState == POWER_ON) {
            System.out.println("调高音量");
        }
    }


    public static void main(String[] args){
        TvControllerNomal mTvControllerNomal = new TvControllerNomal();
        mTvControllerNomal.powerOn();
        mTvControllerNomal.nextChannel();

        mTvControllerNomal.powerOff();
        mTvControllerNomal.nextChannel();
    }

}

执行main方法后,输出信息如下

开机啦
下一频道
关机啦

以下逐渐改造该类为状态模式

  1. 定义电视机状态接口
/**
 * 电视功能接口,定义了电视操作的函数
 * Created by Niwa on 2017/8/20.
 */
public interface TvState {
    void nextChannel();

    void prevChannel();

    void turnUp();

    void turnDown();
}

定义电视机的几个功能

  1. 分别书写电视机的两种状态,开机状态下的功能和关机状态下的功能,开机情况下能操作所有功能,关机情况下,功能无响应
/** 关机状态
 * Created by Niwa on 2017/8/20.
 */
public class PowerOffState  implements TvState{
    @Override
    public void nextChannel() {

    }

    @Override
    public void prevChannel() {

    }

    @Override
    public void turnUp() {

    }

    @Override
    public void turnDown() {

    }
}


/** 关机状态
 * Created by Niwa on 2017/8/20.
 */
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("音量剪");
    }
}
  1. 定义电视的状态接口
/** 电视状态接口
 * Created by Niwa on 2017/8/20.
 */
public interface PowerController {
    void powerOn();
    void powerOff();
}

  1. 书写状态的控制器,实现电视机的状态的接口
/** 电视遥控器,类似于经典状态模式中的Context
 * Created by Niwa on 2017/8/20.
 */
public class TvController implements PowerController {
    TvState mTvState;

    public void setmTvState(TvState mTvState) {
        this.mTvState = mTvState;
    }

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

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

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

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

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

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

  1. 最后在main函数中测试
public static void main(String[] args) {
        TvController tvController = new TvController();
        tvController.powerOn();
        tvController.nextChannel();
        tvController.turnUp();
        tvController.powerOff();
        //调高音量,此时不会生效
        tvController.turnUp();
    }


打印结果:

开机啦
下一频道
音量加
关机啦

UML图

电视机状态模式

定义一个电视机的功能的接口,然后分别对应电视机的开关两个状态实现其功能,然后用TvController(相当于电视机遥控器了)来注入两种状态的类,在TvController具体执行所需要的功能,跟状态模式UML差不多,但意图却完全不一样,策略模式是让用户指定更换的策略算法,而状态模式是状态在满足一定条件下的自动更换,用户无法指定状态,最多只能设置初始状态。

源代码:DesignPattern


参考

《Android源码设计模式解析与实战读书》
各大佬博客


end

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,219评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,363评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,933评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,020评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,400评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,640评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,896评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,597评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,327评论 1 244
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,581评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,072评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,399评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,054评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,849评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,672评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,585评论 2 270

推荐阅读更多精彩内容

  • 设计模式汇总 一、基础知识 1. 设计模式概述 定义:设计模式(Design Pattern)是一套被反复使用、多...
    MinoyJet阅读 3,820评论 1 15
  • 设计模式基本原则 开放-封闭原则(OCP),是说软件实体(类、模块、函数等等)应该可以拓展,但是不可修改。开-闭原...
    西山薄凉阅读 3,669评论 3 13
  • 面向对象的六大原则 单一职责原则 所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于...
    JxMY阅读 885评论 1 3
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • 我静坐在星巴克里,轻轻拿勺搅拌着咖啡。空气中弥漫着80℃卡布奇诺的芬芳,我望向窗外,等候着那个人,只是少了从前的那...
    珍珠奶茶只要珍珠阅读 434评论 2 5