设计模式-15-状态模式 State -[行为模式]

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-2 17:12   1873   0

1.状态模式简介

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

2.举例说明

案例:城市的纵向发展离不开电梯,就以电梯为例。
状态\动作开门 关门 运行 停止
开门状态XOXX
关门状态OXOO
运行状态XXXO
停止状态OXOX
状态模式包含三个角
  • Context:它就是那个含有状态的对象,它可以处理一些请求,这些请求最终产生的响应会与状态相关。
  • State:状态接口,它定义了每一个状态的行为集合,这些行为会在Context中得以使用。
  • ConcreteState:具体状态,实现相关行为的具体状态类。

下面我们已代码分别说明:

环境角色Context
/**
 * 环境角色Context
 *
 * 首先定义出电梯的所有状态,然后定义当前电梯状态,
 * 再定义四种状态对应的方法,如Openning状态是由open()方法产生的。
 * 至于这些方法中的逻辑,就用print来代替了。
 */
public class A1_Context {

    //定义出电梯的所有状态
    public final static B1_LiftState OPENNING_STATE = new C1_OpenningState();
    public final static B1_LiftState CLOSING_STATE = new C2_ClosingState();
    public final static B1_LiftState RUNNING_STATE = new C3_RunningState();
    public final static B1_LiftState STOPPING_STATE = new C4_StoppingState();

    //定义一个当前电梯状态
    private B1_LiftState liftState;

    public B1_LiftState getLiftState() {
        return liftState;
    }

    public void setLiftState(B1_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();
    }
}
抽象电梯状态LiftState
/**
 * 抽象电梯状态LiftState
 *
 * 这里我们定义并把Context这个环境角色聚合进来,并传递到子类。
 * 所以我们可以这样理解,Context环境角色的作用就是串联各个状态的过渡,
 * 也就是在4个具体的实现类中,各自根据自己的环境来决定如何进行状态的过渡。
 */
public abstract class B1_LiftState {

    /**
     * 持有环境角色Context
     */
    protected A1_Context context;

    public void setContext(A1_Context context) {
        this.context = context;
    }

    //电梯门开启动作
    public abstract void open();

    //电梯门关闭动作
    public abstract void close();

    //电梯运行
    public abstract void run();

    //电梯停止
    public abstract void stop();
}
电梯开门状态
/**
 * 电梯开门状态
 */
public class C1_OpenningState extends B1_LiftState {

    /**
     * 执行打开电梯门方法
     */
    @Override
    public void open() {
        System.out.println("电梯门开启");
    }

    /**
     * 打开后还可以关闭电梯门
     */
    @Override
    public void close() {
        //状态修改
        super.context.setLiftState(A1_Context.CLOSING_STATE);
        //动作委托为CLOSING_STATE执行
        super.context.getLiftState().close();
    }

    /**
     * 门开着不能运行
     */
    @Override
    public void run() {
        //什么都不做
    }

    /**
     * 门开着已经停止了(开门的时候门就是停止的)
     */
    @Override
    public void stop() {
        //什么都不做
    }
}
电梯闭门状态
/**
 * 电梯闭门状态
 */
public class C2_ClosingState extends B1_LiftState {

    /**
     * 电梯门关了可以再开
     */
    @Override
    public void open() {
        //置为开门状态
        super.context.setLiftState(A1_Context.OPENNING_STATE);
        super.context.getLiftState().open();
    }

    /**
     * 执行电梯门关闭方法
     */
    @Override
    public void close() {
        System.out.println("电梯门关闭");
    }

    /**
     * 电梯门关了就可以运行
     */
    @Override
    public void run() {
        super.context.setLiftState(A1_Context.RUNNING_STATE);
        super.context.getLiftState().run();
    }

    /**
     * 电梯门关了但没有按楼层
     */
    @Override
    public void stop() {
        super.context.setLiftState(A1_Context.STOPPING_STATE);
        super.context.getLiftState().stop();
    }
}
电梯运行状态
/**
 * 电梯运行状态
 */
public class C3_RunningState extends B1_LiftState {

    /**
     * 运行时不能开门
     */
    @Override
    public void open() {
        //什么都不做
    }

    /**
     * 运行时门肯定是关的
     */
    @Override
    public void close() {
        //什么都不做
    }

    /**
     * 执行运行方法
     */
    @Override
    public void run() {
        System.out.println("电梯运行中");
    }

    /**
     * 运行后可以停止
     */
    @Override
    public void stop() {
        //环境设置为停止状态
        super.context.setLiftState(A1_Context.STOPPING_STATE);
        super.context.getLiftState().stop();
    }
}
电梯停止状态
/**
 * 电梯停止状态
 */
public class C4_StoppingState extends B1_LiftState {

    /**
     * 停下了要开门
     */
    @Override
    public void open() {
        super.context.setLiftState(A1_Context.OPENNING_STATE);
        super.context.getLiftState().open();
    }

    /**
     * 门本来就是关着的
     */
    @Override
    public void close() {
        //什么都不做
    }

    /**
     * 停止后可以再运行
     */
    @Override
    public void run() {
        super.context.setLiftState(A1_Context.RUNNING_STATE);
        super.context.getLiftState().run();
    }

    /**
     * 执行停止方法
     */
    @Override
    public void stop() {
        System.out.println("电梯停止了");
    }
}

客户端调用:

public class D1_Client {

    public static void main(String[] args) {
        A1_Context context = new A1_Context();

        //定义初始状态为关门(共四种初始值)
        context.setLiftState(new C4_StoppingState());
        context.open();
        context.close();
        context.run();
        context.stop();
    }
}
电梯门开启
电梯门关闭
电梯运行中
电梯停止了

3.状态模式主要解决的问题

对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。

4.状态模式的使用场景

  1. 行为随状态改变而改变的场景。
  2. 条件(if..else)、分支(switch)语句的代替者。

5.状态模式的优点

  • 1:对状态转换规则进行了封装;
  • 2:可以使用枚举类,枚举出所有可能的状态。但是需要在枚举状态之前确定状态的种类;
  • 3:扩展性好。将所有与某个或者某些状态有关的行为放到了一个类对象中,这样方便管理,并且可以方便的新增状态,只需要改变对象状态就可以实现改变对象行为了;
  • 4:代码简洁好维护。状态模式允许状态转换逻辑和状态对象合为一体,而不是一个巨大的条件语句块;
  • 5:可以让多个不同的环境对象共享一个状态的对象,这样减少系统中对象的数量。

6.状态模式的缺点

  • 1:增加对象和系统类的个数;
  • 2:结构与实现比较复杂,如果使用不当,可能会造成程序结构和代码给人感觉很混乱的;
  • 3:对开闭原则支持不好。

使用状态模式需要注意事项:
在行为受到状态约束的时候,使用状态模式,而且需要注意的是:状态最好不要超过5个;

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP