c++ 设计模式_行为型设计模式 状态模式

author zong
email zongzhe1996@163.com

写在前面

本文主要是作者在学习设计模式过程中的笔记,主要用来记录思路,文中出现的代码并没有在IDE中进行编译运行,只能保证符合作者的思路,并不是最优解决方案。

1.介绍

状态设计模式,是一种行为型设计模式,类的行为基于类的状态进行改变。

2.意图

允许对象在内部状态发生改变的时候,根据状态调整内部行为。

3.解决问题

对象的行为依赖于对象的状态(属性)。

4.何时使用

代码中包含大量与对象状态有关的条件语句(if-else或者switch)。

5.基本结构

状态设计模式的核心,是将类的不同状态与不同状态下的行为单独封装,通过在不同状态下使用不同的类,实现行为的切换。

d753d4d94f75542435b04bb5693b027d.png

如图所示, State接口是状态的顶层接口, State接口中定义了所有状态的通用接口 doAction()AConcreteState类和 BConcreteState类分别是 State接口的两个具体实现类。通过在 AConcreteState类和 BConcreteState类中对 doAction()接口进行不同的实现,为不同状态下的类定义不同的行为。

Context类为状态的拥有者,负责根据实际情况进行状态的管理包括状态切换,状态获取等。

6.Running Example

通过一个Example,对状态设计模式进行详细说明。

void judgeType(InputContent ic){

if(ic.A.getResult==True){

System.out.println("A is true")

ic.A.run();

}

if(ic.B.getId==1){

System.out.println("B is 1")

ic.B.run();

}

if(ic.C.getContent!=null){

System.out.println("C is not void")

ic.C.run();

}

}


如上所示,函数 judgeType根据传入参数ic中成员A,B,C的不同情况,分别采取了不同的行为。但是在上述 if-else的结构中,如果再增加对ic.D的判断,则需要修改源代码,违背了面向对象设计原则中的开闭原则。因此,需要使用状态设计模式对上述代码进行重构。

首先,对 judgeType中的状态进行抽象,目前包含三个状态:1) A is True. 2) B id is 1. 3) C content is not null. 因此,状态类的结构设计如下:

public interface State{

}

//A is True

public class ATrueState implements State{

}

//B id is 1.

public class BId1State implements State{

}

//C content is not null

public class CContentNoNullState implements State{

}

其次,定义 JudgeType类,并将状态接口作为 JudgeType类的内部成员。

public class JudgeType{

private State state;

private InputContent ic;

public JudgeType(){

this.state=new ATrueState();

}

public InputContent getIC(){

return ic;

}

public void setIC(InputContent icIn){

this.ic=icIn;

}

public State getState(){

return this.state;

}

public void setState(State stateIn){

this.state=stateIn;

}

}

然后,对不同状态对应的抽象行为进行抽象,将 ic作为通过接口 doAction的传入参数,结果如下:

public interface State{

public void doAction(JudgeType jt);

}

//A is True

public class ATrueState implements State{

public void doAction(JudgeType jt){

if(jt.getIC.A.getResult==True){

System.out.println("A is true")

jt.getIC.A.run();

jt.setState(new BId1State);

}

else{

jt.setState(new BId1State);

}

}

}

//B id is 1.

public class BId1State implements State{

public void doAction(JudgeType jt){

if(jt.getIC.B.getID==1){

System.out.println("B is 1")

jt.getIC.B.run();

jt.setState(new CContentNoNullState);

}

else{

jt.setState(new CContentNoNullState);

}

}

}

//C content is not null

public class CContentNoNullState implements State{

public void doAction(JudgeType jt){

if(jt.getIC.C.getID==1){

System.out.println("C is not void");

jt.getIC.C.run();

System.out.println("Finish!");

}

else{

System.out.println("Finish!");

}

}

}

最后,将主函数中调用函数 JudgeType的地方调整如下:

void main(InputContent icIn){

JudgeType jt=new JudgeType();

jt.setIC(icIn);

jt.getState().doAction();

}

最后,通过一张执行流程图,展示状态模式的工作流程。

fa48ca7af95a1c2e61e4d2df0064bcb3.png

如图所示在, StateDesignPattern中,在主函数中1创建 JudgeType对应示例,并通过构造函数设置默认状态为 ATrueState,然后通过2将计算过程中需要使用的参数 icIn传入,并通过3调用 getState接口获取到当前状态,通过调用当前状态的 doAction执行状态对应的具体行为。然后在状态 ATrueState中如果if判定条件达成则执行动作,并通过 setState接口将当前状态设置为 BId1State,如果if判定条件没有达成,则直接通过 setState接口将当前状态设置为 BId1State。如果起始状态为 BId1State,则采用相同的过程,最后将状态调整为 CContentNoNullState

整个执行过程与 if-else中的执行流程相同,但是,状态设计模式的引入,使得添加新的 if-else分支不需要改动原有代码,只需要创建一个新的state并实现原有的State接口与行为接口 doAction即可。

如果添加新分支,对D的name进行判断,在 if-else中实现这个功能的话,修改如下:

void judgeType(InputContent ic){

if(ic.A.getResult==True){

System.out.println("A is true")

ic.A.run();

}

if(ic.B.getId==1){

System.out.println("B is 1")

ic.B.run();

}

if(ic.C.getContent!=null){

System.out.println("C is not void")

ic.C.run();

}

//新添加的D分支

if(ic.D.getName="new"){

System.out.println("D is a new case")

ic.D.run();

}

}


if-else中添加新分支必须要对原有代码产生修改,而状态设计模式需要进行的调整如下:

//C content is not null

public class CContentNoNullState implements State{

public void doAction(JudgeType jt){

if(jt.getIC.C.getID==1){

System.out.println("C is not void");

jt.getIC.C.run();

//设置下一个新添加的条件为DIsNewState

jt.setState(new DIsNewState);

}

else{

jt.setState(new DIsNewState);

}

}

}

//D is a new case

//为新添加的D分支创建新的状态类

public class DIsNewState implements State{

public void doAction(JudgeType jt){

if(jt.getIC.D.getName=="new"){

System.out.println("D is a new case");

jt.getIC.D.run();

System.out.println("Finish!");

}

else{

System.out.println("Finish!");

}

}

}

但是,从上面的例子可以看到,还是需要对状态 CContentNoNullState进行一点小修改才能在使用的过程中成功的跳转到状态 DIsNewState。这里的主要原因是因为我们在最先设计这个案例的过程中忽略了状态的迁移过程,将状态的迁移过程内置在状态当中,使状态迁移过程与状态内部行为的实现过程耦合。针对这个问题,我们将状态的迁移过程单独抽象为一个链表,并将其保存在 JudgeType类中,以此来实现状态迁移过程与状态内部行为实现的解耦。整个状态设计模式调整如下:

首先,在 JudgeType类中添加状态链表与状态相关操作,如跳转,添加等。(还可以根据实际需求添加)

public class JudgeType{

private State state;

private InputContent ic;

public JudgeType(){

this.state=new ATrueState();

}

public InputContent getIC(){

return ic;

}

public void setIC(InputContent icIn){

this.ic=icIn;

}

public State getState(){

return this.state;

}

public void setState(State stateIn){

this.state=stateIn;

}

//添加状态链表,并添加相关操作

private List<State> statesList;

private static int stateIndex=0;

public void addState(State stateIn){

this.statesList.add(stateIn);

}

public void toNext(){

stateIndex++;

this.state=stateList.get(i);

}

}

其次,将所有 doAction中调用的 setState接口,修改为 toNext接口。以此实现将具体跳转到某个状态的操作,封装到 toNext中。

public interface State{

public void doAction(JudgeType jt);

}

//A is True

public class ATrueState implements State{

public void doAction(JudgeType jt){

if(jt.getIC.A.getResult==True){

System.out.println("A is true")

jt.getIC.A.run();

//setState --> toNext

jt.toNext();

}

else{

//setState --> toNext

jt.toNext();

}

}

}

//B id is 1.

public class BId1State implements State{

public void doAction(JudgeType jt){

if(jt.getIC.B.getID==1){

System.out.println("B is 1")

jt.getIC.B.run();

//setState --> toNext

jt.toNext();

}

else{

//setState --> toNext

jt.toNext();

}

}

}

//C content is not null

public class CContentNoNullState implements State{

public void doAction(JudgeType jt){

if(jt.getIC.C.getID==1){

System.out.println("C is not void");

jt.getIC.C.run();

//setState --> toNext

jt.toNext();

}

else{

//setState --> toNext

jt.toNext();

}

}

}

//D is a new case

public class DIsNewState implements State{

public void doAction(JudgeType jt){

if(jt.getIC.D.getName=="new"){

System.out.println("D is a new case");

jt.getIC.D.run();

//setState --> toNext

jt.toNext();

}

else{

//setState --> toNext

jt.toNext();

}

}

}

最后在主函数中,每次添加新的 if-else分支,都可以创建一个新的状态类,并将对应的状态类示例添加到链表中。

void main(InputContent icIn){

JudgeType jt=new JudgeType();

//添加新分支D

jt.addState(new DIsNewState());

jt.setIC(icIn);

jt.getState().doAction();

}

7.总结

  1. 使用状态设计模式取代 if-else和 switch,需要将不同的条件,封装为不同的状态类,将不同条件对应的行为,封装到不同的状态类中。

  2. 需要注意的几个要点:

  • 状态管理者/使用者即本文中的 JudgeType类,要作为每个状态类行为接口 doAction的传入参数,同时状态管理者还要内置状态接口的引用 state

  • 状态管理者可以将内置的所有状态保存在队列,链表一类的数据结构中,并提供相应的操作接口。

  • 将if分支的每次判断封装到对应的状态类中,并在状态类中完成对应行为后,及时切换到对应状态。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值