了解23种设计模式之状态模式
什么是状态模式
状态模式(State): 当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类
在软件开发中,有些对象可能会根据不同的情况做出不同的行为,我们把这种对象称为有状态的对象,而把影响对象行为的一个或多个动态变化的属性称为状态。当有状态的对象与外部事件产生互动时,其内部状态会发生改变,从而使得其行为也随之发生改变。如人的情绪有高兴的时候和伤心的时候,不同的情绪有不同的行为,当然外界也会影响其情绪变化。
对这种有状态的对象编程,传统的解决方案是:将这些所有可能发生的情况全都考虑到,然后使用 if-else 语句来做状态判断,再进行不同情况的处理。但当对象的状态很多时,程序会变得很复杂。而且增加新的状态要添加新的 if-else 语句,这违背了“开闭原则”,不利于程序的扩展。
状态模式主要解决的是当控制一个对象转态转换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同的状态的一系列类当中,可以把复杂的判断逻辑简化。当然,如果这个状态判断很简单,那就没必要用状态模式了。状态模式把受环境改变的对象行为包装在不同的状态对象里,其意图是让一个对象在其内部状态改变的时候,其行为也随之改变。
状态模式的角色与特点`
优点
:
1,状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足“单一职责原则”。
2,减少对象间的相互依赖。将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖。
3,有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换
缺点
1,状态模式的使用必然会增加系统的类与对象的个数。
2,状态模式的结构与实现都较为复杂,如果使用不当会导致程序结构和代码的混乱
角色
:
环境(Context)角色
:也称为上下文,它定义了客户感兴趣的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理。抽象状态(State)角色
:定义一个接口,用以封装环境对象中的特定状态所对应的行为。具体状态(Concrete State)角色
:实现抽象状态所对应的行为。
结构图如下:
代码实现
抽象状态(State)角色`:定义一个接口,用以封装环境对象中的特定状态所对应的行为。
public abstract class State {
public abstract void Handler(Context context);
}
具体状态(Concrete State)角色
:实现抽象状态所对应的行为。
public class ConcretStateA extends State{
@Override
public void Handler(Context context) {
System.out.println("当前状态是 A.");
context.setState( new ConcretStateB());
}
}
具体状态(Concrete State)角色
:实现抽象状态所对应的行为。
public class ConcretStateB extends State{
@Override
public void Handler(Context context) {
System.out.println("当前状态是 B.");
context.setState( new ConcretStateA());
}
}
上下文:它定义了客户感兴趣的接口,维护一个当前状态,并将与状态相关的操作委托给当前状态对象来处理。
public class Context {
private State state;
public Context(State state) {
this.state = state;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public void request(){
state.Handler(this);
}
}
测试结果
public class MainClass {
public static void main(String[] args) {
//创建环境
Context context=new Context(new ConcretStateA());
context.request();
context.request();
context.request();
context.request();
}
}
状态模式应用实例
例:工作转态:上午,中午,下午,晚上,下班,睡眠 六个状态
public abstract class State {
public abstract void writeCode(Work work);
}
public class ForenoonState extends State {
@Override
public void writeCode(Work work) {
if(work.getHour()<12){
System.out.println("当前时间: "+work.getHour()+",上午工作,精神百倍");
}else{
work.setState(new NooState());
work.writeParameter();
}
}
}
public class NooState extends State{
@Override
public void writeCode(Work work) {
if(work.getHour()<14){
System.out.println("当前时间: "+work.getHour()+",中午饿了,吃午饭,睡觉");
}else{
work.setState(new AfternoonState());
work.writeParameter();
}
}
}
public class AfternoonState extends State{
@Override
public void writeCode(Work work) {
if(work.getHour()<18){
System.out.println("当前时间: "+work.getHour()+",下午工作");
}else{
work.setState(new EveningState());
work.writeParameter();
}
}
}
public class EveningState extends State{
@Override
public void writeCode(Work work) {
if(work.getFinish()){
work.setState(new RestState());
work.writeParameter();
}else{
work.setState(new SleepingState());
work.writeParameter();
}
}
}
public class RestState extends State{
@Override
public void writeCode(Work work) {
System.out.println("当前时间"+work.getHour()+"下班休息");
}
}
public class SleepingState extends State {
@Override
public void writeCode(Work work) {
System.out.println("加班干活");
}
}
public class Work {
/**
* 工作时长
*/
private double hour;
/**
* 工作是否完成
*/
private Boolean finish = false;
private State state;
public Work(State state) {
this.state = state;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public double getHour() {
return hour;
}
public void setHour(double hour) {
this.hour = hour;
}
public Boolean getFinish() {
return finish;
}
public void setFinish(Boolean finish) {
this.finish = finish;
}
public void writeParameter() {
state.writeCode(this);
}
}
测试
public class MainClass {
public static void main(String[] args) {
State state = new ForenoonState();
Work w = new Work(state);
w.setHour(11);
w.writeParameter();
w.setHour(13);
w.writeParameter();
w.setHour(16);
w.writeParameter();
/*w.setHour(18);
w.writeParameter();*/
w.setHour(18);
w.setFinish(true);
w.writeParameter();
}
}
模式的应用场景
1,当一个对象的行为取决于它的状态,并且它必须在运行时根据状态改变它的行为时,就可以考虑使用状态模式。
2,一个操作中含有庞大的分支结构,并且这些分支决定于对象的状态时。