状态模式的定义:

  状态模式也叫作状态机模式,运行对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类,属于行为型设计模式。

  状态模式中类的行为是由状态决定的,在不同的状态下有不同的行为。其意图是让一个对象在其内部改变的时候,行为也随之改变。

状态模式的核心是装态与行为绑定,不同的状态对应不同的行为。

状态模式的应用场景:

  • 行为随状态改变而改变的场景。
  • 一个操作中含有庞大的多分支结构,并且这些分支取决于对象的状态。

状态模式的UML类图:

  状态模式的UML类图就不画了,因为它和策略模式的UML类图基本一致,它们都包含三个角色,

其中环境类角色(Context)分别是负责切换策略和状态,抽象角色分别是定义不同策略和不同状态

的行为,具体角色分别是策略的具体实现和状态的具体实现,唯一的区别是状态模式在完成某个状态

的行为之后还有可能会切换到其他状态。

使用状态模式实现登录状态自由切换:

  当我们浏览博客园的文章时,如果我们觉得文章很好,忍不住想评论、收藏。但是如果我们处于未登录的状态,就会自动跳转到登录页面

这里涉及到的状态有两种登录和未登录,行为有评论和收藏。下面使用状态模式来实现这个逻辑,代码如下。

首先创建抽象状态角色类,定义评论和收藏两个行为

public abstract class UserState {
    protected AppContext context;

    public void setContext(AppContext context) {
        this.context = context;
    }

    public abstract void favorite();

    public abstract void comment(String comment);
}

然后创建未登录状态类,定义在未登录状态下,两种行为的具体实现

public class UnLoginState extends UserState {

    @Override
    public void favorite() {
        this.switch2login();
        this.context.getState().favorite();
    }

    @Override
    public void comment(String comment) {
        this.switch2login();
        this.context.getState().comment(comment);
    }

    private void switch2login(){
        System.out.println("跳转到登录页!");
        this.context.setState(this.context.STATE_LOGIN);
    }
}

创建登录状态类,定义在登录状态下,两种行为的具体实现

public class LoginState extends UserState {
    @Override
    public void favorite() {
        System.out.println("收藏成功!");
    }

    @Override
    public void comment(String comment) {
        System.out.println(comment);
    }
}

创建上下文角色类,根据登录状态切换具体的行为

public class AppContext {

    public static final UserState STATE_LOGIN = new LoginState();
    public static final UserState STATE_UNLOGIN = new UnLoginState();

    private UserState currentState = STATE_UNLOGIN;

    {
        STATE_LOGIN.setContext(this);
        STATE_UNLOGIN.setContext(this);
    }

    public void setState(UserState state){
        this.currentState = state;
    }

    public UserState getState(){
        return this.currentState;
    }

    public void favorite(){
        this.currentState.favorite();
    }

    public void comment(String comment){
        this.currentState.comment(comment);
    }
}

最后编写客户端测试代码。

public class Test {
    public static void main(String[] args) {
        AppContext context = new AppContext();
        context.favorite();
        context.comment("评论:好文章,360个赞");
    }
}

状态模式和责任链模式的区别:

  • 状态模式和责任链模式都能消除if...else分支过多的问题。但是在某些情况下,状态模式中的状态可以理解为责任,那么这种情况下,两种模式都可以使用。
  • 从定义上来看,状态模式强调的是一个对象内在状态的改变,而责任链模式强调的是外部节点对象间的改变。
  • 从代码实现上来看,两者最大的区别就是状态模式的各个状态对象知道自己要进入的下一个状态对象,而责任链模式并不清楚其下一个节点处理对象,因为链式组装由客户端负责。

状态模式和策略模式的区别:

  状态模式和策略模式的UML类图架构几乎完全一样,但两者的应用场景是不一样的。策略模式的多种算法行为则其一都能满足,彼此之间是独立的,用户可自行更换策略算法;而

状态模式的各个状态之间存在相互关系,彼此之间一定的条件下存在自动切换的效果,并且用户无法指定状态,只能设置初始状态,因为状态是根据行为而改变的。

状态模式的优点:

  • 结构清晰:将状态独立为类,清楚了冗余的if...else或switch...case语句,使代码更加间接,提高了系统的可维护性。
  • 将状态转换现实化:通常对象内部都是使用数值类型来定义状态的,状态的切换通过赋值进行表现,不够直观;而使用状态类,当切换状态时,是以不同的类进行表示的,转换目的更加明确。
  • 状态类职责明确且具备扩展性。

状态模式的缺点:

  • 类膨胀,如果一个类的状态过多,则会造成状态类过多。
  • 状态模式的结构和实现都较为复杂,如果使用不当,将导致程序结构和代码的混乱。
  • 状态模式对开闭原则的支持不太友好,如果新增了状态类,则需要修改负责切换到该类的状态类。而且修改某个状态的行为也要修改源码。