zoukankan      html  css  js  c++  java
  • 状态模式

    一、概述

    一般问题:同一个对象因内部环境变化而展现出完全不同的表示。

    核心方案:允许一个对象在其内部状态改变时改变它的行为,看起来就像改变了它的类一样。

    设计意图:事物是有状态的,有些类也需要考虑不同状态下表现出完全不同的行为。如果把状态变化直接封装在类内部方法中,我们需要写复杂的条件判断语句——根据不同状态,执行不同的代码逻辑。简单情况这样写没什么问题,如果类的状态变化复杂,条件判断逻辑过于臃肿,就需要考虑引入设计模式了。设计模式的一个原则就是提取变化,既然状态会变化,我们就提取不同状态下的具体实现封装成状态类,用一个状态类实例替换原来复杂的条件判断逻辑。

    状态模式类图:

     

    状态模式优化代码大致模型如下:

    原代码:

        int mState = 0;
        private void method () {
            //复杂的条件判断
            if (mState == 1) {
                //do state1
            } else if (mState == 2) {
                //do state2
            } else if (mState == 3) {
                //do state3
            } else {
                //do default
            }
        }

    状态模式代码:

        State mState;
        private void method(){
            mState.method();   //直接执行state方法,替代复杂的条件判断
        }
    
        //公开设置state接口
        public void setState(State state){
            mState = state;
        }

     二、应用实战

    在手机上经常能收到商品链接,点击链接后可以查看商品详细信息,这时如果点击购买或评价,就需要判断用户是否为登陆状态:登陆状态和非登陆状态是两种完全不同的处理结果。这里可以运用状态模式来解耦客户端和用户状态变化,其类图如下:

     

    首先抽象出用户状态类:

    public interface UserState {
      /**
       * 购买
       */
      public void buy(Context context);
      /**
       * 评论
       */
      public void comment(Context context);
    }

    然后定义状态子类——登陆状态:

    public class LogIn implements UserState{
      @Override
      public void buy(Context context) {
        gotoPayActivity(); //进入支付界面
      }
      @Override
      public void comment(Context context) {
        gotoCommentActivity(); //进入评论界面
      }
    }

    继续定义状态子类——非登陆状态:

    public class LogOut implements UserState{
      @Override
      public void buy(Context context) {
        gotoLogInActivity(); //进入登陆界面
      }
      @Override
      public void comment(Context context) {
        gotoLogInActivity();  //进入登陆界面
      }
    }

    客户端Context类如下:

    public class Context {
      //默认为非登录状态
      UserState state = new LogOut();
    
      //设置登陆状态
      public void setState(UserState state){
        this.state = state;
      }
      //购买
      public void buy(Context context){
        state.buy(context);
      }
      //评论
      public void comment(Context context){
        state.comment(context);
      }
    }

    可以看出,Context不用写复杂的登陆判断语句,也不用关心用户具体登陆状态,实现了与用户状态解耦。

    另外,如果现在要增加一个状态,比如账号冻结状态,只需要新增一个状态子类就行。


    三、总结

    总结:状态模式是一种行为型设计模式,主要解决的是当控制一个对象状态的条件表达式过于复杂时,把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。

    用一句话概括状态模式:

    万变不离其宗

    优点:

    • 简化了状态判断代码
    • 将调用者与被调用者状态解耦

    缺点:每一种状态对应一个子类,造成状态子类繁多

  • 相关阅读:
    mybatis中_parameter使用和常用sql
    ibatis中井号跟美元符号区别(#.$)
    mybatis动态sql中的trim标签的使用
    c语言捕捉异常
    lua lua解读
    lua luaconf解读
    android堆栈调试--详细
    cocos2d-x安卓应用启动调用过程简析
    ndk-stack使用方法
    cocos2dx3.2移植android
  • 原文地址:https://www.cnblogs.com/not2/p/11082925.html
Copyright © 2011-2022 走看看