首先,状态模式是23中设计模式中的一种,在状态模式(State Pattern)中,类的行为是基于它的状态改变的。这种类型的设计模式属于行为型模式。在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。状态模式一般和对象的状态有关。实现类的方法有不同的功能,覆盖接口中的方法。
意图:允许对象在内部状态发生改变时改变它的行为,对象看起来好像修改了它的类。
主要解决:对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。
何时使用:代码中包含大量与对象状态有关的条件语句。根据不同的状态来进行不同的动作。
如何解决:将各种具体的状态类抽象出来。
可以消除if。。。。else。。。语句,尤其是当多个if。。。else。。。语句时以及多个条件。
优点: 1、封装了转换规则。 2、枚举可能的状态,在枚举状态之前需要确定状态种类。 3、将所有与某个状态有关的行为放到一个类中,并且可以方便地增加新的状态,只需要改变对象状态即可改变对象的行为。 4、允许状态转换逻辑与状态对象合成一体,而不是某一个巨大的条件语句块。 5、可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
缺点: 1、状态模式的使用必然会增加系统类和对象的个数。 2、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱。 3、状态模式对"开闭原则"的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源代码,否则无法切换到新增状态,而且修改某个状态类的行为也需修改对应类的源代码。
假设现在我们有一个饮水机,它有以下两个状态: 满桶,空桶。初始状态是满桶,容量是20。饮水机只有一个动作:press,每次press后都会使容量减1,一旦为0,则将状态设置为空桶,这时press没有水流出。
要使用状态模式,我们必须明确两个东西:状态和每个状态下执行的动作。就像是饮水机,最基本的状态就是满桶和空桶,而这两个状态下,都可能要执行倒水这个动作,也就是press。如果饮水机的容量为0,则会进入空桶的状态。
在状态模式中,因为所有的状态都要执行相应的动作,所以我们可以考虑将状态抽象出来。
状态的抽象一般有两种形式:接口和抽象类。如果所有的状态都有共同的数据域,可以使用抽象类,但如果只是单纯的执行动作,就可以使用接口。
这里我们就用接口。
public interface DispenserState { void press(); }
然后我们再定义满桶和空桶两个状态:
public class FullState implements DispenserState { @Override public void press() { System.out.println("Water is pouring!"); } } public class NullState implements DispenserState { @Override public void press() { System.out.println("There is not water poured!"); } }
接着我们再实现饮水机:
public class WaterDispenser { private static int capacity = 20; private static DispenserState dispenserState; public WaterDispenser(DispenserState state) { dispenserState = state; } private static void setState(DispenserState state) { dispenserState = state; } public DispenserState getState() { return dispenserState; } public void press() { capacity--; if (capacity <= 0) { setState(new NullState()); } dispenserState.press(); } }
接着我们再进行测试:
public class Test { public static void main(String[] args) { WaterDispenser dispenser = new WaterDispenser(new FullState()); for (int i = 0; i < 100; ++i) { dispenser.press(); } } }
这是一个非常简单的应用场景:我们不断的press,饮水机里的水会越来越少,从满桶状态变成空桶状态。
如果我们不使用状态模式,也可以解决这个问题:
public class WaterDispenser {
private static int capacity = 20;
public void press() {
capacity--;
if (capacity <= 0) {
System.out.println("There is not water poured!");
} else {
System.out.println("Water is pouring!");
}
}
}
这样一看可能感觉还是if。。。else。。。更简单,但是想一下,如果这里的20,不是容量,而是20个条件进行不一样的操作呢,那么就会有20个if。。。else。。。语句,然后每个语句里进行一大堆的操作么?
但是有一点,就是每增加一种状态的话,就会增加一个类,所以我们所要维护的类就也在不断的增加,并且增加系统的复杂性。
转载自: