本文已参与「新人创作礼」活动,一起开启掘金创作之路。
状态模式属于对象行为型模式
一 由来
在软件开发过程中,应用程序中的部分对象可能根据不同的情况作出不同的行为,我们把这种对象称为有状态的对象,而把影响对象行为的一个或多个动态变化的属性称为状态。
当有状态的对象与外部事件产生互动时,其内部状态就会发生改变,从而使其行为也发生改变。
对这种有状态的对象编程,传统的解决方案是使用条件判断,但显然这种做法对复杂的状态判断存在弊端,条件判断过于臃肿,可读性差,且不具备扩展性,维护难度也大。且增加新的判断还要添加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();
}
}