状态模式,是一种行为模式,在软件开发过程中,对象按照不同的情况做出不同的行为,我们把这样的对象称为具有状态的对象,而把影响对象行为的一个或者多个动态变化的属性称为状态。
对这种具有状态的对象变成,传统的解决方案是,将这些所有可能发生情况全部考虑到,然后使用if-else或者switch-case语句来做状态判断,再进行不同情况的处理。但是这种情况存在一个弊端,就是,条件判断语句会过于浮肿,可读性差,并且不具备拓展性,维护难度也将加大,并且增加新的状态时需要添加新的if-else语句,这违背了“开闭原则”,并不利于程序的拓展。
状态模式:它允许对象在内部状态改变时改变其行为。状态模式将状态和对应的行为封装成不同的状态对象,使得对象的行为可以根据不同的状态进行动态切换。
状态模式的核心组成部分包括:
状态接口(State Interface):定义了状态对象的接口,包含了对象在该状态下可以执行的方法。
具体状态类(Concrete State):实现了状态接口,在具体的状态下定义了对象的行为。
环境类(Context):包含了一个状态对象,并维护当前的状态,可以根据不同的状态调用相应的方法。
状态模式的主要优点包括:
将状态和行为分离:将不同的状态封装成不同的对象,使得状态和行为可以独立变化,提高了代码的灵活性和可维护性。
简化条件语句:通过状态对象的切换来替代复杂的条件语句,使得代码更加清晰和易懂。
符合开闭原则:增加新的状态类不会修改已有的代码,只需要添加新的状态类和相应的转换规则。
关于状态模式的限制和适用场景:
可能增加对象的数量:每个状态都需要一个对应的状态类,可能会增加对象的数量。
当状态比较少且相对简单时,使用状态模式可能会增加代码的复杂性。
状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。
/**
* 抽象状态(State)角色:定义一个接口,用以封装环境对象中的特定状态所对应的行为,可以有一个或多个行为。
*/
public interface State {
//行为动作...
public void doAction(Context context);
}
/**
* 具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。
* 这里代表游戏玩家开始的状态.
*/
public class StartState implements State {
@Override
public void doAction(Context context) {
System.out.println("玩家处理于启动状态,开始相应操作");
//给上下文对象设定对应的状态对象,然后在 context执行对应的操作
// 这里避免了使用 if...else 这样的判断语句.
context.setState(this);
}
@Override
public String toString(){
return "开始状态";
}
}
/**
* 环境类(Context)角色:也称为上下文,它定义了客户端需要的接口,内部维护一个当前状态,并负责具体状态的切换。
*
* 状态机
*/
public class Context {
/**
* ******* 状态
*/
private State state;
public Context(){
state = null;
}
//******状态修改
public void setState(State state){
this.state = state;
//TODO:在这里可以加入 状态修改后的进一步的操作...
//修改状态 -> 触发事件 -> 消息通知 -> 操作 -> 状态改变.
// a -> e1 -> b
// b -> e2 -> c
}
public State getState(){
return state;
}
}
public class StatePatternDemo {
public static void main(String[] args) {
Context context = new Context();
//注意比较: 以下状态发生变化时,无须要用 if..else做状态判断.
//设置状态为开始.
StartState startState = new StartState();
startState.doAction(context);
System.out.println(context.getState().toString());
//修改状态为 stop
StopState stopState = new StopState();
stopState.doAction(context);
System.out.println(context.getState().toString());
}
}
/**
* 具体状态(Concrete State)角色:实现抽象状态所对应的行为,并且在需要的情况下进行状态切换。
* 停止状态
*/
public class StopState implements State {
@Override
public void doAction(Context context) {
System.out.println("Player is in stop state");
//给上下文对象设定对应的状态对象,然后在 context执行对应的操作
// 这里避免了使用 if...else 这样的判断语句.
context.setState(this);
}
@Override
public String toString(){
return "Stop State";
}
}
路才刚刚开始走,怎么能半路放弃呢?听我所听,做我想做,梦我想梦,也许几年后我看到这句话会把他删掉,也许他就这么挂在这里,一直挂着。我与众生皆为凡人,无高低贵贱,他擅他长,吾擅吾长,何须羡慕他人等?身在其位,专攻其事,如若不善,辞职跑路!何须压抑与心之久,于己不快哉,长路漫漫有人陪同吾亦乐之,无人陪同吾亦独行,彼岸花开,终有一日,吾亦赏之。