1. 引入状态模式
(该例子引入《大话设计模式》)
作为程序员,加班是家常便饭。我们就每日的工作状态写一下。
9:00-11:00 上午上班
11:00-13:00 午休
13:00-18:00 下午上班
18:00 下班
18:00 以后 加班
用代码表示如下:
public class WholeWork {
private int hour;
private boolean finished;
public void writeProgram() {
hour = this.getHour();
if(hour<11) {
System.out.println(hour+"点了,上午上班中");
} else if(hour<13) {
System.out.println(hour+"点了,午休中");
} else if(hour<18) {
System.out.println(hour+"点了,下午上班中");
} else{
if(finished) {
System.out.println(hour+"点了,下班了");
} else {
if(hour<21) {
System.out.println(hour+"点了,加班中");
}else {
System.out.println(hour+"点了,还在持续加班中,太困了,要睡着了");
}
}
}
}
public int getHour() {
return hour;
}
public void setHour(int hour) {
this.hour = hour;
}
public boolean isFinished() {
return finished;
}
public void setFinished(boolean finished) {
this.finished = finished;
}
}
测试类:
public class WholeTest {
public static void main(String[] args) {
WholeWork work = new WholeWork();
work.setHour(9);
work.writeProgram();
work.setHour(12);
work.writeProgram();
work.setHour(16);
// work.setFinished(true);
work.writeProgram();
work.setHour(20);
work.writeProgram();
work.setHour(23);
work.writeProgram();
}
}
结果:
需求达到了,但从代码可以看出这么几个问题:
- WholeWork类中的writeProgram方法过长,if判断分支过多,责任过大,所有的逻辑判断都写在这个方法里,违背了单一职责原则。
- 如果修改需求,比如说改成17:30下班,或者要求21点前必须下班,修改需求后,需要做的改动比较大,这就违背了开放-封闭原则。
为了解决这种要求在不同状态下需要发生不同的行为,这就需要一种新的模式——状态模式。
2. 状态模式
2.1 定义
状态模式,当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。(引自《大话设计模式》)
2.2 解释
其实,就是说当一个对象的状态转换的条件表达式过于复杂时,可以将状态变化的判断逻辑转移到其他一系列类中去。就比如说上面的例子,9:00-11:00,11:00-13:00,等等,有这么多的状态条件判断,我们可以把这些判断分散到一系列类中,这样不仅解了耦,代码也变得简单明了,方便维护。
当然了,这里只适用状态判断复杂的情况,如果情况简单,比如只需要两个判断,那么if-else就可以搞定了,无需什么状态模式了。
2.3 结构图
- Context类,上下文,定义状态。
- State类,抽象状态类,或接口类,定义了一个与Context状态相关联的行为方法。
- ConcreteState类,具体实现类,实现State的方法,实现与Context状态相关联的行为方法。
2.4 基本代码
State
public interface State {
void handle(Context context);
}
Context上下文,定义了状态
public class Context {
public State state;
public Context(State state) {
this.state = state;
}
public void request() {
state.handle(this);
}
}
ConcreteStateA,具体状态类,每一个子类实现一个与Context相关的行为。在handle方法中设置ConcreteStateA的下一状态为ConcreteStateB。
public class ConcreteStateA implements State {
@Override
public void handle(Context context) {
System.out.println("开始做A了");
context.state = new ConcreteStateB();
}
}
ConcreteStateB具体状态类
public class ConcreteStateB implements State {
@Override
public void handle(Context context) {
System.out.println("开始做B了");
}
}
测试类
public class StateTest {
public static void main(String[] args) {
Context context = new Context(new ConcreteStateA());//设置初始状态为ConcreteStateA
context.request();
context.request();
context.request();
}
}
结果:
3. 应用
就用状态模式改编一下上面关于工作状态的代码。直接上代码~
State类,抽象接口。
public interface State {
void writeProgram(Work work);
}
Work类,就是上面的Context。定义了hour和finished,即需要不断变换的条件。维护了State接口。
public class Work {
public State state;
public int hour;
public boolean finished = false;
public Work(State state) {
this.state = state;
}
public void request() {
state.writeProgram(this);
}
public int getHour() {
return hour;
}
public void setHour(int hour) {
this.hour = hour;
}
public boolean isFinished() {
return finished;
}
public void setFinished(boolean finished) {
this.finished = finished;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
}
具体实现类A
public class MorningState implements State {
@Override
public void writeProgram(Work work) {
int hour = work.getHour();
if(hour<11) {
System.out.println(hour+"点了,上午工作中");
}else {
work.setState(new NoonState());
work.request();
}
}
}
具体实现类B
public class NoonState implements State {
@Override
public void writeProgram(Work work) {
int hour = work.getHour();
if(hour<13) {
System.out.println(hour+"点了,中午休息中");
}else {
work.setState(new AfternooState());
work.request();
}
}
}
具体实现类C
public class AfternooState implements State {
@Override
public void writeProgram(Work work) {
int hour = work.getHour();
if(hour<18) {
System.out.println(hour+"点了,下午工作中");
}else {
work.setState(new EveningState());
work.request();
}
}
}
具体实现类D
public class EveningState implements State {
@Override
public void writeProgram(Work work) {
if(work.isFinished()) {
work.setState(new RestState());
work.request();
} else {
int hour = work.getHour();
if(hour<21) {
System.out.println(hour+"点了,夜晚加班中,累。。。");
}else {
work.setState(new SleepingState());
work.request();
}
}
}
}
具体实现类E
public class SleepingState implements State {
@Override
public void writeProgram(Work work) {
if(work.isFinished()) {
work.setState(new RestState());
work.request();
} else {
int hour = work.getHour();
System.out.println(hour+"点了,还在加班中,要睡着了。。。");
}
}
}
具体实现类F
public class RestState implements State {
@Override
public void writeProgram(Work work) {
System.out.println(work.getHour()+"点了,下班了。");
}
}
这里,我们将不同状态下所影响的行为分别封装在了子类ABCDEF中,实现具体的接口方法writeProgram。
测试类
public class StateTest {
public static void main(String[] args) {
Work work = new Work(new MorningState());//设置初始状态为上午
work.setHour(9);
work.request();
work.setHour(12);
work.request();
work.setHour(15);
work.request();
//work.setFinished(true);
work.setHour(20);
work.request();
work.setHour(23);
work.request();
}
}
结果:
如果将finished设置为true,则结果为:
完工~
4. 总结
- 消除了庞大的if-else判断,降低了耦合性。
- 将不同状态影响的行为分散到子类中去,增强了扩展性,当有新的状态行为时,只需要增加子类就行了。
- 当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为,这个时候可以考虑用状态模式。
累。。今天先写到这里,我看看,之后有空再补充一个例子进来。
写在最后:
本文主要是小猫看《大话设计模式》的笔记式的记录,方便以后查阅。