定义
状态模式也称为状态机模式,时允许对象在内部发生改变时改变它的行为。
状态模式将类的状态与行为进行绑定,类的行为是由状态决定的,不同状态下有不同的行为,意图让一个对象其内部状态改变时,它的行为也发生变化
结构
如上图,状态模式包含下面几个角色
- 抽象状态角色
定义该状态下的行为,行为可以是一个或多个 - 具体状态角色
具体实现该状态对应的行为,在必要时,需要进行状态切换 - 环境类角色
顶一个客户端需要的接口,内部维护一个当前状态的实例,并提供状态切换的入口。代码如下:
package com.lchtest.pattern.statemachine.general.simple;
// 抽象状态
public interface IState {
void handle();
}
package com.lchtest.pattern.statemachine.general.simple;
public class ConcreteStateA implements IState{
@Override
public void handle() {
System.out.println("StateA do action");
}
}
package com.lchtest.pattern.statemachine.general.simple;
public class ConcreteStateB implements IState{
@Override
public void handle() {
System.out.println("StateB do action");
}
}
package com.lchtest.pattern.statemachine.general.simple;
public class Context {
private static final IState STATE_A = new ConcreteStateA();
private static final IState STATE_B = new ConcreteStateB();
// 设置默认状态
private IState currentState = STATE_A;
// 用户切换状态
public void setState(IState state){
System.out.println("用户切换状态");
this.currentState = state;
}
public void handle(){
this.currentState.handle();
}
}
package com.lchtest.pattern.statemachine.general.simple;
public class Test {
public static void main(String[] args) {
Context context = new Context();
// 使用默认状态
context.handle();
// 切换状态为ConcreteStateB
context.setState(new ConcreteStateB());
context.handle();
}
}
输出
StateA do action
用户切换状态
StateB do action
使用场景
当控制一个对象的状态的表达式过于复杂时,通常把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的逻辑简单化。对象的行为依赖于它的状态(属性),状态的改变会引起行为的改变。因此状态模式适用于下面场景:
- 行为跟随状态变化而改变的场景,如电商系统订单状态流转,工作流等
- 一个操作中含有庞大的多分支机构,具体执行哪个分支取决于对象的状态
代码示例
用一个论坛发表评论,收藏的例子来说明,用户登录后,可以直接评论,收藏文章,未登录时,跳转到登陆页面进行登录后才能进行评论,收藏操作:这里登录状态对应的行为是收藏,评论,未登录状态对应的行为是登录
创建抽象状态角色类:
package com.lchtest.pattern.statemachine.discuz;
/**
* 抽象状态
*/
public abstract class UserState {
// 上下文,子类需要引用
protected AppContext appContext;
public void setAppContext(AppContext appContext) {
this.appContext = appContext;
}
// 状态下的行为
public abstract void favourite();
public abstract void comment(String comment);
}
创建登录状态类:
package com.lchtest.pattern.statemachine.discuz;
/**
* 具体状态1- 登陆状态
*/
public class LoginState extends UserState {
@Override
public void favourite() {
System.out.println("收藏成功");
}
@Override
public void comment(String comment) {
System.out.println("评论成功:" + comment);
}
}
未登录状态
package com.lchtest.pattern.statemachine.discuz;
/**
* 具体状态2- 未登陆状态
*/
public class UnLoginState extends UserState {
@Override
public void favourite() {
this.switchToLogin();
this.appContext.getState().favourite();
}
@Override
public void comment(String comment) {
this.appContext.getState().comment(comment);
}
// 用户切换状态
private void switchToLogin(){
System.out.println("切换状态,跳转到登陆页面");
// 切换状态
this.appContext.setState(this.appContext.SATE_LOGIN);
}
}
上下文角色:
package com.lchtest.pattern.statemachine.discuz;
public class AppContext {
public static final UserState SATE_LOGIN = new LoginState();
public static final UserState SATE_UNLOGIN = new UnLoginState();
// 设置默认状态
private UserState currentState = SATE_UNLOGIN;
{
SATE_LOGIN.setAppContext(this); // 初始化状态
SATE_UNLOGIN.setAppContext(this);
}
// 提供用户切换状态的方法
public void setState(UserState state) {
this.currentState = state;
}
// 提供用户获取当前状态的方法
public UserState getState() {
return this.currentState;
}
// 用户操作入口;状态的流转是系统内部决定的,而不是用户可以操作的!
public void favourate() {
this.currentState.favourite();
}
public void comment(String comment) {
this.currentState.comment(comment);
}
}
测试
package com.lchtest.pattern.statemachine.discuz;
public class Test {
public static void main(String[] args) {
AppContext context = new AppContext();
context.favourate();
context.comment("评论:良心文章");
}
}
状态机模式案例链接:
【设计模式】学习笔记14:状态模式(State)