设计模式 状态模式的由来、状态模式和策略模式的区别

145 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

状态模式属于对象行为型模式

一 由来

在软件开发过程中,应用程序中的部分对象可能根据不同的情况作出不同的行为,我们把这种对象称为有状态的对象,而把影响对象行为的一个或多个动态变化的属性称为状态。

当有状态的对象与外部事件产生互动时,其内部状态就会发生改变,从而使其行为也发生改变。

对这种有状态的对象编程,传统的解决方案是使用条件判断,但显然这种做法对复杂的状态判断存在弊端,条件判断过于臃肿,可读性差,且不具备扩展性,维护难度也大。且增加新的判断还要添加if else语句,违背了“开闭原则”,不利于程序的扩展。

以上问题可以使用状态模式解决

状态模式的解决思想是:

当控制一个对象状态转换的条件表达式过于复杂时,把相关判断逻辑提取出来,用各个不同的类表示。

二 适用场景

当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式了。

三 示例1

比如,小明七点起床这个行为,平时要上班的时候,闹铃一响,小明七点就起来了。

但是,周末休息的时候,小明打死也起不来。

package com.qing.state0;

public abstract class State {

    abstract void getUpAtSeven();
}
package com.qing.state0;

public class WorkdaysState extends State{
    @Override
    void getUpAtSeven() {
        System.out.println("七点起床成功");
    }
}
package com.qing.state0;

public class WeekendState extends State {
    @Override
    void getUpAtSeven() {
        System.out.println("七点起床失败");
    }
}
package com.qing.state0;

public class Context {
    private State state;

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

    public void doSth(){
        state.getUpAtSeven();
    }
}

 测试

package com.qing.state0;

public class Test1 {
    public static void main(String[] args) {
        Context xiaoming = new Context();
        xiaoming.setState(new WeekendState());
        xiaoming.doSth();
        xiaoming.setState(new WorkdaysState());
        xiaoming.doSth();
    }

}

结果

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

策略模式做的都是同一件事

例如,聚合支付平台,有支付宝、微信支付、银联支付,虽然策略不同,但最终做的事情都是支付,也就是说他们之间是可替换的。

 状态模式是不同状态下做的事情不同

各个状态的同一方法做的是不同的事(做事的结果不一样),不能互相替换。
比如,用户只有在登录之后才可以下单采购,未登录时不能下单采购。   

五 示例2

比如,用户登录后可以添加商品到购物车、购买
用户未登录时不能添加商品到购物车、不能购买,需要引导用户登录。
用户默认状态是未登录状态。

package com.qing.state;

public abstract class UserState {

    //上下文对象,存有当前用户的状态
    protected Context context;
    
    public void setContext(Context context) {
        this.context = context;
    }
    
    public abstract void addToShoppingCart();
    public abstract void buy();

}
package com.qing.state;

public class LoginState extends UserState {
    @Override
    public void addToShoppingCart() {
        System.out.println("加入购物车成功");
    }

    @Override
    public void buy() {
        System.out.println("购买成功");
    }
}
package com.qing.state;

public class NotLoginState extends UserState {
    @Override
    public void addToShoppingCart() {
        this.jumpLogin();
        this.context.getState().addToShoppingCart();
    }

    @Override
    public void buy() {
        this.jumpLogin();
        this.context.getState().buy();
    }

    private void jumpLogin(){
        System.out.println("请先登录,跳转到登录页面");
        //TODO:执行登录操作
        //登录完成之后,修改状态
        this.context.setState(Context.STATE_LOGIN);
    }
}
package com.qing.state;

public class Context {
    //两种状态:登录和未登录
    public static final UserState STATE_LOGIN = new LoginState();
    public static final UserState STATE_NOTLOGIN = new NotLoginState();

    //初始是未登录状态
    private UserState currentState = STATE_NOTLOGIN;

    //实例代码块,在构造方法之前执行,给state设置context
    {
        STATE_LOGIN.setContext(this);
        STATE_NOTLOGIN.setContext(this);
    }

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

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

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

}

测试

package com.qing.state;

public class Test1 {
    public static void main(String[] args) {
        Context context = new Context();
        context.addToShoppingCart();
        context.buy();
    }
}