行为型设计模式-状态模式

Posted vbirdbest

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了行为型设计模式-状态模式相关的知识,希望对你有一定的参考价值。

一:案例

电梯功能,电梯状态分为:开门、关门、运行、停止4个状态,不同的状态下支持的操作是不同的。

/**
 * 电梯接口
 */
public interface ILift 
    int OPENING_STATE = 1;
    int CLOSING_STATE = 2;
    int RUNNING_STATE = 3;
    int STOPPING_STATE = 4;

    // 设置电梯状态的功能
    void setState(int state);

    void open();
    void close();
    void run();
    void stop();

/**
 * 电梯类
 */
public class Lift implements ILift 
    private int state;

    @Override
    public void setState(int state) 
        this.state = state;
    

    //执行关门动作
    @Override
    public void close() 
        switch (this.state) 
            case OPENING_STATE:
                System.out.println("电梯关门了。。。");//只有开门状态可以关闭电梯门,可以对应电梯状态表来看
                this.setState(CLOSING_STATE);//关门之后电梯就是关闭状态了
                break;
            case CLOSING_STATE:
                //do nothing //已经是关门状态,不能关门
                break;
            case RUNNING_STATE:
                //do nothing //运行时电梯门是关着的,不能关门
                break;
            case STOPPING_STATE:
                //do nothing //停止时电梯也是关着的,不能关门
                break;
        
    

    //执行开门动作
    @Override
    public void open() 
        switch (this.state) 
            case OPENING_STATE://门已经开了,不能再开门了
                //do nothing
                break;
            case CLOSING_STATE://关门状态,门打开:
                System.out.println("电梯门打开了。。。");
                this.setState(OPENING_STATE);
                break;
            case RUNNING_STATE:
                //do nothing 运行时电梯不能开门
                break;
            case STOPPING_STATE:
                System.out.println("电梯门开了。。。");//电梯停了,可以开门了
                this.setState(OPENING_STATE);
                break;
        
    

    //执行运行动作
    @Override
    public void run() 
        switch (this.state) 
            case OPENING_STATE://电梯不能开着门就走
                //do nothing
                break;
            case CLOSING_STATE://门关了,可以运行了
                System.out.println("电梯开始运行了。。。");
                this.setState(RUNNING_STATE);//现在是运行状态
                break;
            case RUNNING_STATE:
                //do nothing 已经是运行状态了
                break;
            case STOPPING_STATE:
                System.out.println("电梯开始运行了。。。");
                this.setState(RUNNING_STATE);
                break;
        
    

    //执行停止动作
    @Override
    public void stop() 
        switch (this.state) 
            case OPENING_STATE: //开门的电梯已经是是停止的了(正常情况下)
                //do nothing
                break;
            case CLOSING_STATE://关门时才可以停止
                System.out.println("电梯停止了。。。");
                this.setState(STOPPING_STATE);
                break;
            case RUNNING_STATE://运行时当然可以停止了
                System.out.println("电梯停止了。。。");
                this.setState(STOPPING_STATE);
                break;
            case STOPPING_STATE:
                //do nothing
                break;
        
    

Lift类中的每个方法都会出现大量的switch或者 if else,这看上去代码不够优雅。

二:定义

对有状态的对象,把复杂的判断逻辑提取到不同的状态对象中,运行状态对象在其内部状态发生改变时改变其行为。

三:状态模式实现

状态模式就是把原来的case或者if else if 分支都抽象成一个对象。

/**
 * 抽象状态类
 */
public abstract class LiftState 
	// 用于被子类继承
    protected Context context;
    public void setContext(Context context) 
        this.context = context;
    

    public abstract void open();
    public abstract void close();
    public abstract void run();
    public abstract void stop();


/**
 * 开启状态
 */
public class OpeningState extends LiftState 
    @Override
    public void open() 
        System.out.println("电梯开启...");
    

    @Override
    public void close() 
        // 修改了liftState的指向对象
        super.context.setLiftState(Context.CLOSING_STATE);
        // 调用修改后的状态对应的方法
        super.context.close();
    

    @Override
    public void run() 
        // 什么都不做
    

    @Override
    public void stop() 
        // 什么都不做
    


---
/**
 * 关闭状态
 */
public class ClosingState extends LiftState
    @Override
    public void open() 
        super.context.setLiftState(Context.OPENING_STATE);
        super.context.open();
    

    @Override
    public void close() 
        System.out.println("电梯关门了...");
    

    @Override
    public void run() 
        super.context.setLiftState(Context.RUNNING_STATE);
        super.context.run();
    

    @Override
    public void stop() 
        super.context.setLiftState(Context.STOPPING_STATE);
        super.context.stop();
    



---
/**
 * 运行状态
 */
public class RunningState extends LiftState
    @Override
    public void open() 
        // do nothing
    

    @Override
    public void close() 
        // do nothing
    

    @Override
    public void run() 
        System.out.println("电梯正在运行...");
    

    @Override
    public void stop() 
        super.context.setLiftState(Context.STOPPING_STATE);
        super.context.stop();
    


---
/**
 * 停止状态
 */
public class StoppingState extends LiftState
    @Override
    public void open() 
        super.context.setLiftState(Context.OPENING_STATE);
        super.context.open();
    

    @Override
    public void close() 
        super.context.setLiftState(Context.CLOSING_STATE);
        super.context.close();
    

    @Override
    public void run() 
        super.context.setLiftState(Context.RUNNING_STATE);
        super.context.run();
    

    @Override
    public void stop() 
        System.out.println("电梯停止了...");
    

然后引入一个上下文作为代理,

/**
 * 环境角色类
 */
public class Context 

    public final static OpeningState OPENING_STATE = new OpeningState();
    public final static ClosingState CLOSING_STATE = new ClosingState();
    public final static RunningState RUNNING_STATE = new RunningState();
    public final static StoppingState STOPPING_STATE = new StoppingState();

    private LiftState liftState;

    public LiftState getLiftState() 
        return liftState;
    

    public void setLiftState(LiftState liftState) 
        this.liftState = liftState;
        this.liftState.setContext(this);
    

    public void open() 
        this.liftState.open();
    

    public void close() 
        this.liftState.close();
    

    public void run() 
        this.liftState.run();
    

    public void stop() 
        this.liftState.stop();
    



客户端的操作都要使用上下文来操作。

public class Client 
    public static void main(String[] args) 
        Context context = new Context();
        context.setLiftState(new RunningState());

        context.open();
        context.close();
        context.run();
        context.stop();
    

优缺点

优点:

  • 将原来的条件语句块改为对象的方式
  • 将原因的条件状态转换逻辑与状态对象何为一体,消掉了条件语句块。

缺点:

  • 增加系统类的个数
  • 状态模式的结构与实现都比较复杂(Context持有LiftState,LiftState持有Context),如果使用不当将导致程序结构和代码混乱
  • 状态模式对开闭原则的支持不好

使用场景

  • 当一个对象的行为取决于它的状态,并且必须在运行时根据状态改变它的行为时就可以考虑使用状态模式。
  • 一个操作中含有庞大的分支结构,并且这些分支结构决定与对象的状态时。

以上是关于行为型设计模式-状态模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式 行为型模式 -- 状态模式

从零开始学习Java设计模式 | 行为型模式篇:状态模式

从零开始学习Java设计模式 | 行为型模式篇:状态模式

跟我学Java设计模式第6天:行为型设计模式汇总源码

二十三种设计模式[20] - 状态模式(State Pattern)

设计模式系列 - 行为型模式(下)