1、基本概念
状态模式( State Pattern )也称为状态机模式(State Machine Pattern) ,是允许对象在内
部状态发生改变时改变它的行为,对象看起来好像修改了它的类,属于行为型模式。
场景实例:订单的状态改变,工作流程的状态改变
2、类图和角色
类图:
看起来和策略模式很像,抽象,具体,上下文三个对象
角色:
上下文context : 负责维护一个当前状态对象和具体实例状态的切换
抽象状态类:定义状态下的行为
具体状态类:具体状态下行为的实现,并进行状态的切换
3、案例
案例:一个app,用户评论一篇文章,如果用户没有登录,就让其跳转到登录页面进行登录,成功后,切换当前的状态位已登录用户
示意图:
类图:
抽象状态:接口IUserStatus,定义一个统一的接口方法
public interface IUserStatus { void comment(String msg); }
抽象状态:抽象类UserStatus
public abstract class UserStatus implements IUserStatus{ protected Context context; public void setContext(Context context){ this.context = context; } public abstract void comment(String msg); }
具体抽象:登录状态类LoginStatus
public class LoginStatus extends UserStatus { @Override public void comment(String msg) { System.out.println("登录用户xxx:"+msg); } }
具体抽象:未登录状态类NoLoginStatus ,执行comment方法前,进行状态的切换
public class NoLoginStatus extends UserStatus { @Override public void comment(String msg) { //进行登录后才可评论 System.out.println("系统信息:当前用户未登录,请前往登录"); toLoginOn(); this.context.getCurrentUserStatus().comment(msg); } public void toLoginOn() { //登录,修改状态 this.context.setUserStatus(context.LOGIN_STATUS); System.out.println("系统信息:登录成功"); } }
上下文:Context ,负责状态的切换与获取
public class Context { public static final LoginStatus LOGIN_STATUS = new LoginStatus(); public static final NoLoginStatus NO_LOGIN_STATUS =new NoLoginStatus(); private UserStatus currentUserStatus = NO_LOGIN_STATUS; public Context(){ LOGIN_STATUS.setContext(this); NO_LOGIN_STATUS.setContext(this); } public void setUserStatus(UserStatus userStatus){ this.currentUserStatus = userStatus; this.currentUserStatus.setContext(this); } public UserStatus getCurrentUserStatus(){ return this.currentUserStatus; } }
测试:
public class Test { public static void main(String[] args) { Context context = new Context(); UserStatus userStatus = new NoLoginStatus(); userStatus.setContext(context); userStatus.comment("老铁,666"); } }
输出结果:
系统信息:当前用户未登录,请前往登录
系统信息:登录成功
登录用户xxx:老铁,666
4、优缺点
优点;
1、结构清晰,可以干掉if..else语句, 使代码更加简洁
2、状态类职责明确且具备扩展性。
缺点:不符合开闭原则,当我们需要新增一个管理员状态的对象,就需要在登陆的时候切换状态,
那么我们就需要修改context中的代码和LoginStatus的代码