【趣味设计模式系列】之【状态模式】

1. 简介

状态模式(State Pattern),当一个对象内在状态改变时容许其改变行为,这个对象看起来像改变了其类。简而言之,就是状态的变动引发了行为的变动数据库

2. 图解

下图四辆汽车,分别表明汽车平常的四种状态。
开门状态:
this

关门状态:
设计

飞奔状态:
3d

中止状态:
code

其中,某种特定状态下,都有四个可执行操做,分别是open,close,run,stop,而后作对应的处理得下图所示。
对象

3. 案例实现

类图以下:
blog

  • 定义汽车抽象状态类CarState,持有类型为Context的属性,同时持有四个可执行操做,opencloserunstop方法;
  • 定义汽车抽象状态类的子类OpenningStateClosingStateRunningStateStoppingState,分别表明开门状态,关门状态,飞奔状态,中止状态;
  • 定义环境角色类Context,把状态对象声明为静态常量,有几个状态对象就声明几个静态常量,环境角色具备状态抽象角色定义的全部行为,具体执行使用委托方式。具体环境角色有两个职责:处理本状态必须完成的任务,决定是否能够过渡到其余状态。

代码实现以下:get

package com.wzj.state.example1;

/**
 * @Author: wzj
 * @Date: 2019/11/3 20:10
 * @Desc: 汽车状态抽象类
 */
public abstract class CarState {
    //环境角色,封装状态变化引发的行为变化
    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();

}
package com.wzj.state.example1;

/**
 * @Author: wzj
 * @Date: 2019/11/3 20:23
 * @Desc: 汽车开门状态类
 */
public class OpenningState extends CarState {

    //打开汽车门
    public void open() {
        System.out.println("汽车门已开");
    }

    //关闭汽车门
    public void close() {
        //状态修改
        super.context.setCarState(Context.closingState);
        //动做委托为ClosingState来执行
        super.context.getCarState().close();
    }

    //门开着时汽车通常不奔跑
    public void run() {
        System.out.println("汽车开门状态,不能奔跑");
    }

    //车门开着时,切换不到中止状态,由于没有四种状态中,没有开门且中止这个状态
    public void stop() {
        System.out.println("汽车开门状态,不能长时间开着门且处于中止状态");

    }
}
package com.wzj.state.example1;

/**
 * @Author: wzj
 * @Date: 2019/11/3 20:23
 * @Desc: 汽车飞奔状态类
 */
public class RunningState extends CarState {

    //打开奔跑时不开门
    public void open() {
        System.out.println("车在飞奔,不能打开");
    }

    //奔跑时确定是关门的
    public void close() {
        System.out.println("车在飞奔,已经关闭,不能再次关闭");
    }

    //汽车在飞奔
    public void run() {
        System.out.println("汽车在飞奔");
    }

    //汽车能够停下来
    public void stop() {
        //修改汽车为中止状态
        super.context.setCarState(Context.stoppingState);
        //中止动做委托为StoppingState类来执行
        super.context.getCarState().stop();
    }
}
package com.wzj.state.example1;

/**
 * @Author: wzj
 * @Date: 2019/11/3 20:23
 * @Desc: 汽车关门状态类
 */
public class ClosingState extends CarState {

    //打开汽车门
    public void open() {
        //修改汽车为开门状态
        super.context.setCarState(Context.openningState);
        //动做委托为OpenningState类来执行
        super.context.getCarState().open();
    }

    //关闭汽车门
    public void close() {
        System.out.println("汽车门已关");
    }

    //汽车在飞奔
    public void run() {
        //修改汽车为飞奔状态
        super.context.setCarState(Context.runningState);
        //动做委托为RunningState类来执行
        super.context.getCarState().run();

    }

    //汽车在中止
    public void stop() {
        //设置汽车状态为中止状态
        super.context.setCarState(Context.stoppingState);
        //动做委托为StoppingState类来执行
        super.context.getCarState().stop();

    }
}
package com.wzj.state.example1;

/**
 * @Author: wzj
 * @Date: 2019/11/3 20:19
 * @Desc: 上下文环境类
 */
public class Context {

    /**列出汽车全部状态
     * openningState-开门状态 closingState-关门状态
     * runningState-奔驰状态 stoppingState-中止状态
     */
    public static final OpenningState openningState = new OpenningState();
    public static final ClosingState closingState = new ClosingState();
    public static final RunningState runningState = new RunningState();
    public static final StoppingState stoppingState = new StoppingState();

    //定义汽车当前状态
    private CarState carState;

    public CarState getCarState() {
        return  carState;
    }

    public void setCarState(CarState carState) {
        this.carState = carState;
        //切换状态
        this.carState.setContext(this);
    }

    //汽车开门
    public void open() {
        this.carState.open();
    }

    //汽车关门
    public void close(){
        this.carState.close();
    }

    //汽车飞奔
    public void run(){
        this.carState.run();
    }

    //汽车中止
    public void stop(){
        this.carState.stop();
    }

}

客户端类以下:it

package com.wzj.state.example1;

/**
 * @Author: wzj
 * @Date: 2019/11/3 21:06
 * @Desc:
 */
public class Client {
    public static void main(String[] args) {
        Context context = new Context();
        context.setCarState(new OpenningState());
//        context.setCarState(new ClosingState());
//        context.setCarState(new RunningState());
//        context.setCarState(new StoppingState());
        context.open();
//        context.close();
//        context.run();
//        context.stop();
    }
}

执行结果以下:
当只打开Client15行的时候,分别打开11,12,13,14行的代码,会获得以下结果:
汽车为开门状态时,执行open
class

汽车为关门状态时,执行open

汽车为飞奔状态时,执行open

汽车为中止状态时,执行open

上述结果能够看出,一样执行一个open方法,当状态的变化时致使行为的变化。

4. 状态模式总结

优势

  • 结构清晰
    避免了过多的switch...case或者if...else语句的使用,避免了程序的复杂性,提升系统的可维护性;
  • 遵循设计原则
    很好地体现了开闭原则和单一职责原则,每一个状态都是一个子类,你要增长状态就要增长子类,你要修改状态,你只修改一个子类就能够了。
  • 封装性很是好
    这也是状态模式的基本要求,状态变换放置到类的内部来实现,外部的调用不用知道类内部如何实现状态和行为的变换。
    缺点 状态模式既然有优势,那固然有缺点了。但只有一个缺点,子类会太多,也就是类膨胀。若是一个事物有不少个状态也不稀奇,若是彻底使用状态模式就会有太多的子类,很差管理,这个须要你们在项目中本身衡量。其实有不少方式能够解决这个状态问题,如在数据库中创建一个状态表,而后根据状态执行相应的操做,这个也不复杂,看你们的习惯和嗜好了。
相关文章
相关标签/搜索