状态模式(State Pattern) – 设计模式之行为模式

状态模式(State Pattern) – 设计模式之行为模式:

 

目录

状态模式(State Pattern)

类图

例子-审批:

过程:

类图:

代码:

状态 AbstractState

Context定义客户端需要的接口,并且负责具体状态的切换。

主管 SupervisorState

经理 ManagerState

总监 DirectorState

测试:

结果:

分析

优化-审批:

类图:

代码:

状态 State

ApproveContext

主管 SupervisorState

经理 ManagerState

总监 DirectorState

测试:

结果:

总结:

使用场景

对比策略模式


状态模式(State Pattern)

定义: Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.

 当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。  

主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况,把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的判断逻辑简化。

  好处: 将特定状态相关的行为局部化,并且将不同状态的行为分割开来。

  封装基于状态的行为,并将行为委托到当前状态。

 

类图

状态模式通用类图:

 

例子-审批:

过程:

  在工作中,员工出差等需要进行报销审批,审批需要通过主管,经理和总监进行审批。(PS:这里模拟审批状态的一个过程,也没有想到好的状态的一个例子,刚好责任链模式也用这个例子,可以做一个对比。)

 

类图:

 

代码:

状态 AbstractState

接口或抽象类,负责对象状态定义,并且封装环境角色以实现状态切换

public abstract class AbstractState {

  protected Context context;

  public Context getContext() {

    return context;

  }

  public void setContext(Context context) {

    this.context = context;

  }

  public abstract void handle();

}

 

Context定义客户端需要的接口,并且负责具体状态的切换。

public class Context {

    private AbstractState AbstractState;

    public Context() {

    }

    public AbstractState getAbstractState() {

        return AbstractState;

    }

    public void setAbstractState(AbstractState abstractState) {

        this.AbstractState = abstractState;

        this.AbstractState.setContext(this);

    }

    public void request(){

        this.AbstractState.handle();

    }

}

 

每一个具体状态必须完成两个职责:本状态的行为管理以及趋向状态处理,通俗地说,就是本状态下要做的事情,以及本状态如何过渡到其他状态。

主管 SupervisorState

public class SupervisorState extends AbstractState {

    @Override

    public void handle() {

        System.out.println("主管审批通过,下一个经理审批");

        context.setAbstractState(new ManagerState());

    }

}

 

经理 ManagerState

public class ManagerState extends AbstractState {

    @Override

    public void handle() {

        System.out.println("经理审批通过,下一个总监审批");

        context.setAbstractState(new DirectorState());

    }

}

 

总监 DirectorState

public class DirectorState extends AbstractState {

    @Override

    public void handle() {

        System.out.println("总监审批通过,告知财务打款");

        //审核通过之后的逻辑

        System.out.println("财务打款5500元");

    }

}

 

测试:

public class ApproveTest {

    public static void main(String[] args) {

        Context context = new Context();

        context.setAbstractState(new SupervisorState());

        context.request();

        context.request();

        context.request();

    }

}

 

结果:

主管审批通过,下一个经理审批

经理审批通过,下一个总监审批

总监审批通过,告知财务打款

财务打款5500元

 

分析

这个例子中会有一个大的问题,主管类里面依赖了经理的类,增加了耦合度。考虑把下一个状态的过渡,移到context里面进行处理。

优化-审批:

类图:

 

代码:

状态 State

public interface State {

  void changeApprove(ApproveContext context);

}

 

ApproveContext

public class ApproveContext {

  private State state;

  // 默认一个状态初始值,常态

  public ApproveContext() {

    state = new SupervisorState();

    this.state.changeApprove(this);

  }

  public void approveNext() {

    if (state.getClass().equals(SupervisorState.class)) {

      changeStateToNext(new ManagerState());

    } else  if (state.getClass().equals(ManagerState.class)){

      changeStateToNext(new DirectorState());

    }

  }

  private void changeStateToNext(State newState) {

    this.state = newState;

    this.state.changeApprove(this);

  }

  @Override

  public String toString() {

    return "申请报销 ";

  }

}

 

把状态如何过渡到其他状态的控制移到context里面进行处理

主管 SupervisorState

public class SupervisorState implements State {

  @Override

  public void changeApprove(ApproveContext context) {

    System.out.println(context+"主管审批通过,下一个经理审批");

    context.approveNext();

  }

}

 

经理 ManagerState

public class ManagerState implements State {

  @Override

  public void changeApprove(ApproveContext context) {

    System.out.println(context+"经理审批通过,下一个总监审批");

    context.approveNext();

  }

}

 

总监 DirectorState

public class DirectorState implements State {

  @Override

  public void changeApprove(ApproveContext context) {

    System.out.println(context+"总监审批通过,告知财务打款");

    //审核通过之后的逻辑

    System.out.println("财务打款5500元");

  }

}

 

测试:

public class ApproveTest {

    public static void main(String[] args) {

        ApproveContext context = new ApproveContext();

        context.approveNext();
    }

}

 

结果:

申请报销 主管审批通过,下一个经理审批

申请报销 经理审批通过,下一个总监审批

申请报销 总监审批通过,告知财务打款

财务打款5500元

 

总结:

 在实际中也很少用到状态模式,更多是学习下状态模式的思维。

优点: 

   1、封装了转换规则。

   2、枚举可能的状态,在枚举状态之前需要确定状态种类。

   3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。

   4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。

   5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。

缺点: 

   1、状态模式的使用必然会增加系统类和对象的个数。

   2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。

   3、状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。

 

 

使用场景

   1, 行为随状态改变而改变的场景

这也是状态模式的根本出发点,例如权限设计,人员的状态不同即使执行相同的行为结

果也会不同,在这种情况下需要考虑使用状态模式。

   2, 条件、分支判断语句的替代者

在程序中大量使用switch语句或者if判断语句会导致程序结构不清晰,逻辑混乱,使用状态模式可以很好地避免这一问题,它通过扩展子类实现了条件的判断处理。

 

对比策略模式

我觉得两者比较相近,最大的区别是状态模式中具体实现类中:本状态如何过渡到其他状态有一个过渡到其它状态的处理。除去这个,就变成策略模式了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

天狼1222

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值