个人觉得这个模式有点难理解,大家做好心里准备!
还是把这张概总图放这里。
状态模式,也是一种行为设计模式。
重点:对象的行为,由其内部的状态决定。内部状态变化,对应的行为改变。
有的小伙伴分不清状态模式
和命令模式
。觉得,一个命令对应了一个操作
和一个状态对一个行为
,在逻辑上一样的。
其实不一样。区别在于:对象的内部状态是变化的。状态变化后,对应的行为也会变化。但这个行为被调用后,对象的内部状态进入下一个状态。状态与下一个状态之间是有关联的。
。
接下来要进一步理解内部状态
的意思。也就是说这个内部状态
的变化是由对象内部触发的。在外部看来,根本无需关系对象是否使用了状态模式,直接调用行为就好!
前面说到状态会从一个状态变为另一个
,并且这个状态是对象内部的一个状态。也就是说,对象内部某时某刻只维护着一种状态。这个状态怎么表示呢?
当然是定义各个状态的抽象接口类,然后各个状态都是实现这个接口类。这样对象维护的状态,只要是这个抽象接口类的类型就可以了。
public interface State {
// TO DO
}
为什么这里要设计一个顶层状态接口呢?主要是因为,要把状态的行为从状态所在的对象上抽离到状态类上。为什么?
如果我们状态所对应的行为在保留在对象上。那么对象在执行行为的时候,就需要判断当前的状态是什么,接着在执行对应的操作。如果这样做,大家能想象到一堆if-else的语句吗?这实在是太糟糕了~
于是乎!状态的行为需要抽离到这个状态类上。因此,我上面才说用接口。其实你用抽象类也可以。主要是把行为给弄到状态类上。
ps:行为抽离到状态类上,不仅是因为对象中,if-else判断状态违背了开闭原则,而且抽离到状态后,对扩展更好,添加新状态和新行为更方便。
我们接着完善状态类。
public interface State {
void doAction(ContextObject contextObject);
}
这里的ContextObject contextObject
就是对象。把它传递过来,主要是方便调用对象的行为。
我们接着把这个对象的类定义出来。
public class ContextObject{
// 对象中维护的状态
private State state;
//设置新状态
public void setState(State state)
{
this.state=state;
}
//读取状态
public State getState()
{
return(state);
}
//处理当前状态对应的行为
public void handle()
{
state.doAction(this);
}
}
现在,我们来实现两个具体的状态类。
class ConcreteStateA extends State
{
public void Handle(ContextObject context)
{
System.out.println("当前状态是 A.");
context.setState(new ConcreteStateB());
}
}
class ConcreteStateB extends State
{
public void Handle(ContextObject context)
{
System.out.println("当前状态是 B.");
context.setState(new ConcreteStateA());
}
}
上面的两个状态:ConcreteStateA
和ConcreteStateB
。它们的行为是:打印当前的状态,并把对象ContextObject的状态变为另一个状态。
让我们来测试下:
public class StateTest {
public static void main(String[] args) {
ContextObject context = new ContextObject();
ConcreteStateA initialState = new ConcreteStateA();
//设置对象的初始状态。
context.setState(initialState);
//开始调用当前状态的行为。
context.handle();
// 执行完上一步,context中的状态变化了。可以接着执行变化后的状态对应的行为。
context.handle();
//还可以接着执行执行。
context.handle();
context.handle();
}
}
运行输出:当前状态是 A.当前状态是 B.当前状态是 A.当前状态是 B.
状态模式的结构不是很好理解。尤其是其与策略模式和命令模式有许多相似的地方。这需要大家对比区分出不同。小二哥后面也会单独写一篇文章来讲它们的区别。
今天要记住的就是:
当使用ContextObject类改变状态时,状态类之间互相不认识,他们直接的依赖关系应该由客户端负责。
当使用具体的State类切换时,状态直接就可能互相认识,一个状态执行完就自动切换到了另一个状态去了。
优缺点
优点
缺点类变多了~~哈哈(放心,你写的内容没有变多哦)
再次强调一下:对象的行为随着状态的变化而不同的情况,请用状态模式。