基于设计模式的学习之旅-----状态模式(附源码)
基于设计模式的学习之旅-----状态模式
1、初识状态模式
按钮来控制一个电梯的状态,一个电梯开们,关门,停,运行。每一种状态改变,都有可能要根据其他状态来更新处理。例如,开门状体,你不能在运行的时候开门,而是在电梯定下后才能开门。
我们给一部手机打电话,就可能出现这几种情况:用户开机,用户关机,用户欠费停机,用户消户,对方正在通话中,已经连接上对方等。 所以当我们拨打这个号码的时候:系统就要判断,该用户是否在开机且不忙状态,又或者是关机,欠费等状态。但不管是那种状态我们都应给出对应的处理操作。
2、什么是状态模式
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
3、模式结构图
4、模式代码事例
4、1涉及到的类,以及类图
MobileContext、AbstractState、CallEndState、CallStartState、ConnectState、WaitState
4、2具体的代码实现
非状态模式实现
/**
* 电话
*
* @author LuXiaoFeng
* @date 2012-12-23
*/
public class Mobile implements IStateConstants {
private int currentState;
public int getCurrentState() {
return currentState;
}
public void setCurrentState(int currentState) {
this.currentState = currentState;
}
public boolean callStart() {
boolean result = false;
LogUtil.printWithSystemOut("开始准备打电话,拨号中");
switch (currentState) {
case callend_state:
break;
case callstart_state:
result = isBusy();
break;
case connect_state:
break;
case wait_state:
break;
default:
break;
}
return result;
}
public void connecting(int connectState) {
switch (connectState) {
case callend_state:
break;
case callstart_state:
break;
case connect_state:
LogUtil.printWithSystemOut("对方电话已经接通,正在聊天ing~");
LogUtil.printWithSystemOut("聊天结束");
break;
case wait_state:
break;
default:
break;
}
}
public void callEnd(int callendState) {
switch (callendState) {
case callend_state:
LogUtil.printWithSystemErr("通话结束");
break;
case callstart_state:
break;
case connect_state:
break;
case wait_state:
break;
default:
break;
}
}
public void waitting(int waitState) {
switch (waitState) {
case callend_state:
break;
case callstart_state:
break;
case connect_state:
break;
case wait_state:
LogUtil.printWithSystemErr("对方正在通话中,请稍后再拨");
break;
default:
break;
}
}
boolean isBusy() {
return true;
}
}
NoPatternRun
状态模式实现
MobileContext
AbstractState
CallEndState
CallStartState
ConnectState
WaitState
PatternRun
4、3事例输出结果
5、模式参与者
C o n t e x t(环境,如MobileContext :定义客户感兴趣的接口,维护State状态集合和当前状态)
S t a t e(状态,如AbstractState :定义一个接口以封装与C o n t e x t的一个特定状态相关的行为)
ConcreteState(状态子类,如ConnectState:每一子类实现一个与C o n t e x t的一个状态相关的行为)
6、模式优缺点
A、它将与特定状态相关的行为局部化,并且将不同状态的行为分割开来
B、它使得状态转换显式化
C、State对象可被共享
D、状态模式的使用必然会增加系统类和对象的个数
E、状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱
7、模式适用性
A、一个对象的行为取决于它的状态, 并且它必须在运行时刻根据状态改变它的行为。
B、一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常 , 有多个操作包含这一相同的条件结构。 S t a t e模式将每一个条件分支放入一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其他对象而独立变化。
8、与其他模式的区别
8.1 责任链模式
职责链模式和状态模式都可以解决If分支语句过多,
从定义来看,状态模式是一个对象的内在状态发生改变(一个对象,相对比较稳定,处理完一个对象下一个对象的处理一般都已确定),
而职责链模式是多个对象之间的改变(多个对象之间的话,就会出现某个对象不存在的现在,就像我们举例的公司请假流程,经理可能不在公司情况),这也说明他们两个模式处理的情况不同。
这两个设计模式最大的区别就是状态模式是让各个状态对象自己知道其下一个处理的对象是谁。
而职责链模式中的各个对象并不指定其下一个处理的对象到底是谁,只有在客户端才设定。用我们通俗的编程语言来说,就是
状态模式:
相当于If else if else;
设计路线:各个State类的内部实现(相当于If,else If内的条件)
执行时通过State调用Context方法来执行。
职责链模式:
相当于Swich case
设计路线:客户设定,每个子类(case)的参数是下一个子类(case)。
使用时,向链的第一个子类的执行方法传递参数就可以。
就像对设计模式的总结,有的人采用的是状态模式,从头到尾,提前一定定义好下一个处理的对象是谁,而我采用的是职责链模式,随时都有可能调整链的顺序。
状态模式和策略模式的最大区别在于它有状态间的切换,一个状态完了,就要切换到它下一个状态。
8.2策略模式
状态模式和策略模式的实现方法非常类似,都是利用多态把一些操作分配到一组相关的简单的类中,因此很多人认为这两种模式实际上是相同的。
然而在现实世界中,策略(如促销一种商品的策略)和状态(如同一个按钮来控制一个电梯的状态,又如手机界面中一个按钮来控制手机)是两种完全不同的思想。当我们对状态和策略进行建模时,这种差异会导致完全不同的问题。例如,对状态进行建模时,状态迁移是一个核心内容;然而,在选择策略时,迁移与此毫无关系。另外,策略模式允许一个客户选择或提供一种策略,而这种思想在状态模式中完全没有。
一个策略是一个计划或方案,通过执行这个计划或方案,我们可以在给定的输入条件下达到一个特定的目标。策略是一组方案,他们可以相互替换;选择一个策略,获得策略的输出。策略模式用于随不同外部环境采取不同行为的场合。我们可以参考微软企业库底层Object Builder的创建对象的strategy实现方式。而状态模式不同,对一个状态特别重要的对象,通过状态机来建模一个对象的状态;状态模式处理的核心问题是状态的迁移,因为在对象存在很多状态情况下,对各个business flow,各个状态之间跳转和迁移过程都是及其复杂的。
例如一个工作流,审批一个文件,存在新建、提交、已修改、HR部门审批中、老板审批中、HR审批失败、老板审批失败等状态,涉及多个角色交互,涉及很多事件,这种情况下用状态模式(状态机)来建模更加合适;把各个状态和相应的实现步骤封装成一组简单的继承自一个接口或抽象类的类,通过另外的一个Context来操作他们之间的自动状态变换,通过event来自动实现各个状态之间的跳转。在整个生命周期中存在一个状态的迁移曲线,这个迁移曲线对客户是透明的。我们可以参考微软最新的WWF 状态机工作流实现思想。
在状态模式中,状态的变迁是由对象的内部条件决定,外界只需关心其接口,不必关心其状态对象的创建和转化;
而策略模式里,采取何种策略由外部条件(C)决定。