一 定义
在软件开发过程中,应用程序可能要根据不同的情况做不同的处理,最直接的解决方法是将这些情况都考虑到,然后在if...else中进行判断,来针对不同的情况做不同的处理。但是复杂情况就不好处理了,随着状态的增加,可能引起很大的修改,程序的可读性、扩展性都会受到影响。
定义:当一个对象的内在状态改变时允许改变其行为,这个对象看起来是改变了其类。
状态模式的核心是封装,状态的变更引起了行为的变更,从外部看起来就好像这个对象对应的类发生了改变一样。
二 模式结构
角色介绍:
- Context:环境类,定义客户端感兴趣的接口,维护一个State子类的实例,这个实例定义了对象的当前状态。
- State:抽象状态类或者状态接口,定义一个或者一组接口,表示该状态下的行为。
- ConcreteStateA、ConcreteStateB:具体状态类,每一个具体的状态类实现抽象State中定义的接口,从而达到不同状态下的不同行为。
三 实例
我们以电梯运行为例,电梯一共四个状态,分别是开门状态,关门状态,运行状态和停止状态。
(1)在开门状态,只能进行关门操作
(2)在关门状态,可以进行开门,运行操作
(3)在运行状态,只能进行停止操作
(4)在停止状态,可以进行运行和开门操作
我们先看第一版实现
- 电梯接口
电梯接口含有电梯的全部状态和开门,关门,运行,停止等几个功能。
public interface ILift {
//电梯的四个状态
int OPENING_STATE = 1; //门敞状态
int CLOSING_STATE = 2; //门闭状态
int RUNNING_STATE = 3; //运行状态
int STOPPING_STATE = 4; //停止状态;
//设置电梯的状态
public void setState(int state);
//首先电梯门开启动作
public void open();
//电梯门有开启,那当然也就有关闭了
public void close();
//电梯要能上能下,跑起来
public void run();
//电梯还要能停下来,停不下来那就扯淡了
public void stop();
}
- 具体的电梯实现
public class Lift implements ILift{
private int state;
@Override
public void setState(int state) {
this.state=state;
}
// 电梯门打开
@Override
public void open() {
switch (state){
case ILift.OPENING_STATE: // 如果是打开状态,本来就是打开的,什么也不用做
break;
case ILift.CLOSING_STATE: // 关闭状态,可以打开
System.out.println("打开电梯门");
setState(ILift.OPENING_STATE);
break;
case ILift.RUNNING_STATE: // 运行状态下是不能打开电梯门的
break;
case ILift.STOPPING_STATE: // 停止状态可以打开电梯门
System.out.println("打开电梯门");
setState(ILift.OPENING_STATE);
break;
}
}
@Override
public void close() {
switch (state){
case ILift.OPENING_STATE: // 打开状态,可以关闭
System.out.println("关闭电梯门");
setState(ILift.CLOSING_STATE);
break;
case ILift.CLOSING_STATE: // 关闭状态,什么都不用做
break;
case ILift.RUNNING_STATE: // 运行状态,本来就是关闭的
break;
case ILift.STOPPING_STATE: // 停止状态,本来就是关闭的
break;
}
}
@Override
public void run() {
switch (state){
case ILift.OPENING_STATE: // 运行状态,不能开门
break;
case ILift.CLOSING_STATE: // 关闭状态,什么都不用做
break;
case ILift.RUNNING_STATE: // 运行状态,什么都不用做
break;
case ILift.STOPPING_STATE: // 运行状态,可以停止
System.out.println("停止电梯");
setState(ILift.STOPPING_STATE);
break;
}
}
@Override
public void stop() {
switch (state){
case ILift.OPENING_STATE: // 停止状态,可以开门
System.out.println("打开电梯");
setState(ILift.OPENING_STATE);
break;
case ILift.CLOSING_STATE: // 关闭状态,什么都不用做
break;
case ILift.RUNNING_STATE: // 停止状态,可以运行
System.out.println("运行电梯");
setState(ILift.RUNNING_STATE);
break;
case ILift.STOPPING_STATE: // 停止状态,什么都不用做
break;
}
}
}
可以看到,在地电梯类的具体实现中,每个功能方法的实现都包含有switch-case语句,如果在增加几个状态,switch-case的分支还会增多,使这个类变的越来越难以维护。
下面我们用状态模式解决上述问题。
- 电梯的状态接口
在该接口中定义该状态的所有行为。
public interface ILiftState {
//首先电梯门开启动作
public void open();
//电梯门有开启,那当然也就有关闭了
public void close();
//电梯要能上能下,跑起来
public void run();
//电梯还要能停下来,停不下来那就扯淡了
public void stop();
}
- 开门状态类
开门状态类实现电梯的状态接口,并完成在此状态下的功能。
public class OpenningState implements ILiftState{
@Override
public void open() {
}
@Override
public void close() {
System.out.println("关闭电梯门");
}
@Override
public void run() {
}
@Override
public void stop() {
}
}
- 关门状态类
public class ClosingState implements ILiftState{
@Override
public void open() {
System.out.println("打开电梯门");
}
@Override
public void close() {
}
@Override
public void run() {
System.out.println("运行电梯");
}
@Override
public void stop() {
}
}
- 运行状态类
public class RunningState implements ILiftState{
@Override
public void open() {
}
@Override
public void close() {
}
@Override
public void run() {
}
@Override
public void stop() {
System.out.println("停止电梯");
}
}
- 停止状态类
public class StoppingState implements ILiftState{
@Override
public void open() {
System.out.println("停打开电梯门");
}
@Override
public void close() {
}
@Override
public void run() {
System.out.println("运行电梯");
}
@Override
public void stop() {
}
}
- 电梯遥控接口
相当于状态模式的Context角色。
public interface ILiftController {
public void setState(ILiftState state);
public void open();
public void close();
public void run();
public void stop();
}
- 电梯遥控具体实现
public class LiftController implements ILiftController{
private ILiftState mLiftState;
@Override
public void setState(ILiftState state) {
this.mLiftState=state;
}
@Override
public void open() {
mLiftState.open();
}
@Override
public void close() {
mLiftState.close();
}
@Override
public void run() {
mLiftState.run();
}
@Override
public void stop() {
mLiftState.stop();
}
}
- 测试代码
LiftController liftController=new LiftController();
liftController.setState(new OpenningState()); // 打开电梯门
liftController.open(); // 此时不会生效
liftController.close();
liftController.run(); // 此时不会生效
liftController.stop(); // 此时不会生效
// 关闭电梯门
liftController.setState(new ClosingState());
liftController.open();
liftController.close(); // 此时不会生效
liftController.run();
liftController.stop(); // 此时不会生效
四 优缺点
- 结构清晰,避免了过多使用switch-case或者if-else,避免了程序的复杂性。
- 遵循设计原则,每个状态都是一个子类,要想增加状态只要增加子类即可,体现了开闭原则和单一职责原则。
缺点:
状态多的时候,子类会膨胀,太多的子类,可能会不利于项目的管理。
网友评论