状态模式

一、概述

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

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

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

状态模式类图:

 

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

原代码:

    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不用写复杂的登陆判断语句,也不用关心用户具体登陆状态,实现了与用户状态解耦。

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


三、总结

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

用一句话概括状态模式:

万变不离其宗

优点:

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

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

 

posted @ 2019-06-25 15:09  西贝雪  阅读(166)  评论(0编辑  收藏  举报