设计模式之状态模式
这里我们用汽车的运动过程来作为一个示例讲解,首先看一段最初始的代码:
public class State_01 {
static class Car {
public void start() {
System.out.println("============启动==========");
}
public void run() {
System.out.println("============行驶==========");
}
public void stop() {
System.out.println("============停止==========");
}
public void openDoor() {
System.out.println("============开门==========");
}
public void closeDoor() {
System.out.println("============关门==========");
}
}
}
如上代码,假设汽车状态切换:门关闭状态->门打开状态->启动状态->运行状态->停止状态,在状态切换时,有些行为是不能发生的,所以要做限制,下面按照上面车辆状态切换,来重构以上代码:
public class State_02 {
static class Car {
public static final int state_start = 1;
public static final int state_run = 2;
public static final int state_stop = 3;
public static final int state_open = 4;
public static final int state_close = 5;
private int state;//当前状态
public void setState(int state){
this.state = state;
}
public void start() {
switch (this.state){
case state_start:break;
case state_run:break;
case state_stop:
this.startActive();
this.setState(state_start);
break;
case state_open:break;
case state_close:
this.startActive();
this.setState(state_start);
break;
default: break;
}
}
public void run() {
switch (this.state){
case state_start:
this.runActive();
this.setState(state_run);
break;
case state_run:break;
case state_stop:
this.runActive();
this.setState(state_run);
break;
case state_open:break;
case state_close:break;
default: break;
}
}
public void stop() {
switch (this.state){
case state_start:break;
case state_run:
this.stopActive();
this.setState(state_stop);
break;
case state_stop:break;
case state_open:break;
case state_close:break;
default: break;
}
}
public void openDoor() {
switch (this.state){
case state_start:break;
case state_run:break;
case state_stop:break;
case state_open:break;
case state_close:
this.openDoorActive();
this.setState(state_open);
break;
default: break;
}
}
public void closeDoor() {
switch (this.state){
case state_start:
break;
case state_run:break;
case state_stop:
break;
case state_open:
this.closeDoorActive();
this.setState(state_close);
break;
case state_close:
break;
default: break;
}
}
private void startActive() {
System.out.println("============启动==========");
}
private void runActive() {
System.out.println("============行驶==========");
}
private void stopActive() {
System.out.println("============停止==========");
}
private void openDoorActive() {
System.out.println("============开门==========");
}
private void closeDoorActive() {
System.out.println("============关门==========");
}
}
public static void main(String[] args) {
Car car = new Car();
car.setState(Car.state_close);
car.openDoor();
car.closeDoor();
car.start();
car.run();
car.stop();
}
}
以上代码的逻辑就是,一开始车门处于关闭状态,这时候可以执行开启车门操作,变为开启状态,然后执行关闭车门操作,变为关闭车门状态,在关闭车门状态下,可以启动汽车,状态变为启动,然后就是行驶,到停止,这就是整个流程。
虽然已经实现功能,但是从以上代码可以知道,这部门代码每个状态切换的方法里面都包含了switch分支,代码显得冗余,尤其如果有新的状态加入,每个switch都要新增一个状态的判断分支,改动过大,所以需要对其进行优化。
就是对状态进行抽象,然后创建子类状态,每个状态类里面都写入各自状态对应的逻辑即可,如下:
public class State_03 {
static abstract class AbstractState{
private Context context;
public void setContext(Context context) {
this.context = context;
}
public abstract void start();
public abstract void run();
public abstract void stop();
public abstract void open();
public abstract void close();
}
static class Context{
public static final AbstractState startState = new StartState();
public static final AbstractState runState = new RunState();
public static final AbstractState stopState = new StopState();
public static final AbstractState openState = new OpenState();
public static final AbstractState closeState = new CloseState();
private AbstractState state;
public AbstractState getState() {
return state;
}
public void setState(AbstractState state) {
this.state = state;
this.state.setContext(this);
}
public void start(){
state.start();
}
public void run(){
state.run();
}
public void stop(){
state.stop();
}
public void open(){
state.open();
}
public void close(){
state.close();
}
}
//启动状态
static class StartState extends AbstractState{
@Override
public void start() {
System.out.println("================启动================");
}
@Override
public void run() {
super.context.setState(Context.runState);
super.context.getState().run();
}
@Override
public void stop() {
super.context.setState(Context.stopState);
super.context.getState().stop();
}
@Override
public void open() {
}
@Override
public void close() {
}
}
//行驶状态
static class RunState extends AbstractState{
@Override
public void start() {
}
@Override
public void run() {
System.out.println("================运行================");
}
@Override
public void stop() {
super.context.setState(Context.stopState);
super.context.getState().stop();
}
@Override
public void open() {
}
@Override
public void close() {
}
}
//停止状态
static class StopState extends AbstractState{
@Override
public void start() {
super.context.setState(Context.startState);
super.context.getState().start();
}
@Override
public void run() {
}
@Override
public void stop() {
System.out.println("===============停止===============");
}
@Override
public void open() {
}
@Override
public void close() {
}
}
//开门状态
static class OpenState extends AbstractState{
@Override
public void start() {
}
@Override
public void run() {
}
@Override
public void stop() {
}
@Override
public void open() {
System.out.println("================开门=================");
}
@Override
public void close() {
super.context.setState(Context.closeState);
super.context.getState().close();
}
}
//启动状态
static class CloseState extends AbstractState{
@Override
public void start() {
super.context.setState(Context.startState);
super.context.getState().start();
}
@Override
public void run() {
}
@Override
public void stop() {
}
@Override
public void open() {
super.context.setState(Context.openState);
super.context.getState().open();
}
@Override
public void close() {
System.out.println("================关门=================");
}
}
public static void main(String[] args) {
Context context = new Context();
context.setState(Context.closeState);
context.open();
context.close();
context.start();
context.run();
context.stop();
}
}
以上代码主要做了一下动作:
- 抽象出状态类,以及抽象方法和依赖的环境类Context(具体调用类)。
- 创建一个环境类Context,内部的方法和抽象状态类一样,且可以设置当前状态,在每个方法内部,都是调用当前状态的对应方法。
- 实现多个具体的状态类,每个状态类都有具体执行动作方法,以及实现该状态下可以切换到哪些状态方法体,并委托给Context来执行。
以上就是状态模式的一个简单的演变过程,官方对状态模式定义:当一个对象内置状态改变时允许其改变行为,这个对象看起来像改变了其类。
状态模式的优点:
- 编码了过多的switch…case或者if…else语句,降低了程序的复杂性,提高了系统可维护性;
- 遵循设计原则,开闭原则和单一职责原则。
- 封装性好
状态模式的缺点:
状态太多的情况,就会导致子类过多(类膨胀)