Part I 什么是状态模式
状态模式允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类 -- 《Head First – Designer Pattern》译本
Part II 状态模式与策略模式的关系
策略模式强调的是对算法的抽象与封装,而状态模式则侧重于当对象内部状态改变时所引起的对象行为的改变!
虽然两种模式的形式和使用上相类似,但是他们所处理的问题是不一样的。
Part III 解决吃饭-工作问题
首先让我们模拟一个场景:
1. 有一个Person的对象;
2. 这个人有两个行为:吃饭 -- 工作;
3. 这个人有三种不同的状态:吃饱 -- 正常 -- 饥饿;
4. 这三种状态的切换如下:
1)吃饱--[工作]--正常;
2)正常--[工作]--饥饿;
3)饥饿--[吃饭]--正常;
4)正常--[吃饭]--吃饱;
相信读者看到这里一定会想:这样太简短不过了,我们给它一个变量来记录他的状态,然后根据变量的值来判断他的行为就可以了!
好,我们就依照这个思路下如下的代码:
package nopattern;
public class Person {
private String state = "normal";
public void eat() {
if (state.equals("hungry"))
System.out.println("终于有吃的了...");
else if (state.equals("normal"))
System.out.println("吃完就变得很饱...");
else if (state.equals("full"))
System.out.println("我不能再吃了...");
else
System.out.println("非人状态不予考虑");
}
public void work() {
if (state.equals("hungry"))
System.out.println("不给我吃我肯定不干...");
else if (state.equals("normal"))
System.out.println("再干下去会变得很饿...");
else if (state.equals("full"))
System.out.println("我可以干更多的活...");
else
System.out.println("非人状态不予考虑");
}
}
然后我们尝试去测试这个类:
package nopattern;
import pattern.state.entity.Person;
public class Test {
public static void main(String[] args) {
Person me = new Person();
me.eat(); // 吃完就变得很饱...
me.eat(); // 我不能再吃了...
me.eat(); // 我不能再吃了...
me.work(); // 我可以干更多的活...
me.work(); // 再干下去会变得很饿...
me.work(); // 不给我吃我肯定不干...
me.eat(); // 终于有吃的了...
me.eat(); // 吃完就变得很饱...
me.eat(); // 我不能再吃了...
}
}
这样看来,我们写的代码真的很完美了,实现了对象状态的改变引起行为上的改变。但是请细心的想一下,在面向对象程序设计中,我们会接触到这样一个名词:单一责任原则,我们所编写的代码,把对象状态的维护交给了Person这个类来负责,这样做合适吗?
退一步来说,当我们的Person有更多的状态时(例如:“饿得快要晕过去了,连吃饭的力气都没有”和“吃饱了撑着,想干活都干不了了”),那我们是不是也要去修改Person类所有与状态有关的行为呢?我们是否真的需要那么多的if-else呢?
现在,面对上面如此糟糕的代码,有砸电脑的冲动吗?
Part IV 用设计模式来解决吃饭-工作问题
相信到这里,读者们肯定会抱怨说:你X的别再给我卖关子了!!!别急,我们先来分析一下状态这个有意思的东西。
首先我们要清楚一件事情,这个人的状态能不能给抽象出来呢?例如在某些状态中,这些状态中会有共性?
那让我们尝试去分离出Hungry、Full和Normal三种状态的共性吧!
package pattern.state.state;
public interface State {
void eat();
void work();
}
有了这个状态的高度抽象,我们还等什么?马上实现我们的三种状态吧!
package pattern.state.state;
import pattern.state.entity.Person;
public class FullState implements State {
private Person me;
public FullState(Person me) {
this.me = me;
}
@Override
public void eat() {
System.out.println("我不能再吃了...");
}
@Override
public void work() {
System.out.println("我可以干更多的活...");
me.setState(me.NORMAL_STATE);
}
}
package pattern.state.state;
import pattern.state.entity.Person;
public class HungryState implements State {
private Person me;
public HungryState(Person me) {
this.me = me;
}
@Override
public void eat() {
System.out.println("终于有吃的了...");
me.setState(me.NORMAL_STATE);
}
@Override
public void work() {
System.out.println("不给我吃我肯定不干...");
}
}
package pattern.state.state;
import pattern.state.entity.Person;
public class NormalState implements State {
private Person me;
public NormalState(Person me) {
this.me = me;
}
@Override
public void eat() {
System.out.println("吃完就变得很饱...");
me.setState(me.FULL_STATE);
}
@Override
public void work() {
System.out.println("再干下去会变得很饿...");
me.setState(me.HUNGRY_STATE);
}
}
上面定义了三种状态,其中有些方法我们还没有提及到的,请继续往下阅读。
package pattern.state.entity;
import pattern.state.state.FullState;
import pattern.state.state.HungryState;
import pattern.state.state.NormalState;
import pattern.state.state.State;
public class Person {
public final State FULL_STATE = new FullState(this);
public final State NORMAL_STATE = new NormalState(this);
public final State HUNGRY_STATE = new HungryState(this);
private State state = NORMAL_STATE;
public void eat() {
state.eat();
}
public void work() {
state.work();
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
}
不错,就是这么的简单。我们现在已经把状态变化的控制从Person类中分离出来了,由我们的State实现类来控制,我们的Person类只关心自己的状态和吃饭工作问题,状态的问题就由状态自己来解决吧!当我们有更多的状态时,我们只需要修改相应变换的状态部分就可以实现状态间的切换,世界变得那么的美好!