您的位置:首页 > 其它

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

2020-01-05 00:13 1246 查看

1. 简介

状态模式(State Pattern),当一个对象内在

状态改变
时允许其
改变行为
,这个对象看起来像改变了其类。简而言之,就是
状态的变更引起了行为的变更

2. 图解

下图四辆汽车,分别代表汽车日常的四种状态。
开门状态:

关门状态:

飞奔状态:

停止状态:

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

3. 案例实现

类图如下:

  • 定义汽车抽象状态类
    CarState
    ,持有类型为
    Context
    的属性,同时持有四个可执行操作,
    open
    close
    run
    stop
    方法;
  • 定义汽车抽象状态类的子类
    OpenningState
    ClosingState
    RunningState
    StoppingState
    ,分别代表开门状态,关门状态,飞奔状态,停止状态;
  • 定义环境角色类
    Context
    ,把状态对象声明为静态常量,有几个状态对象就声明几个静态常量,环境角色具有状态抽象角色定义的所有行为,具体执行使用委托方式。具体环境角色有两个职责:处理本状态必须完成的任务,决定是否可以过渡到其他状态。

代码实现如下:

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();
}

}

客户端类如下:

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();
}
}

执行结果如下:
当只打开

Client
15行的时候,分别打开11,12,13,14行的代码,会得到如下结果:
汽车为开门状态时,执行open

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

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

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

上述结果可以看出,同样执行一个

open
方法,当状态的变化时导致行为的变化。

4. 状态模式总结

优点

  • 结构清晰
    避免了过多的switch...case或者if...else语句的使用,避免了程序的复杂性,提高系统的可维护性;
  • 遵循设计原则
    很好地体现了开闭原则和单一职责原则,每个状态都是一个子类,你要增加状态就要增加子类,你要修改状态,你只修改一个子类就可以了。
  • 封装性非常好
    这也是状态模式的基本要求,状态变换放置到类的内部来实现,外部的调用不用知道类内部如何实现状态和行为的变换。
    缺点
    状态模式既然有优点,那当然有缺点了。但只有一个缺点,子类会太多,也就是类膨胀。如果一个事物有很多个状态也不稀奇,如果完全使用状态模式就会有太多的子类,不好管理,这个需要大家在项目中自己衡量。其实有很多方式可以解决这个状态问题,如在数据库中建立一个状态表,然后根据状态执行相应的操作,这个也不复杂,看大家的习惯和嗜好了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: