美文网首页
(8)状态模式

(8)状态模式

作者: minminaya | 来源:发表于2017-08-20 12:59 被阅读13次

    定义

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

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


    使用场景

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

    • 代码中包含大量与对象“状态”(例如冰箱开机与关机)相关的条件语句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

    相关文章

      网友评论

          本文标题:(8)状态模式

          本文链接:https://www.haomeiwen.com/subject/xghfdxtx.html