? ? ? ?传统编程模型可以采用最经典的状态模式构建状态机,已达到刻画对象生命周期的目的。在这种编程模型中,为了表达一个状态转移需要应用程序员编写下面类似的代码。
例如在Android开放源代码中的StateMachine.java
Java代码?
class="java" name="code"> private class HaltingState extends State { 728 @Override 729 public boolean processMessage(Message msg) { 730 mSm.haltedProcessMessage(msg); 731 return true; 732 } 733 } ... private class QuittingState extends State { 739 @Override 740 public boolean processMessage(Message msg) { 741 return NOT_HANDLED; 742 } 743 }
??
? ? ? ? 这种虽然完全可以表达状态机的语义并且对于生命周期的变化也非常容易扩展。但是存在以下几个缺点:
? ? ? ?Lifecycle的原型在5年前逐渐的演化,从仅仅通过Hash算法进行Transition(转移)的合法性校验,到使用状态模式在processMessage方法中编写更多的业务逻辑。到使用Java Reflection + 动态代理 来进一步简化编程模型,使用元数据描述生命周期,使得生命周期与业务代码分离。再到现如今的通过 Java Instrument在运行时 或者 编译时修改class字节码,以便去掉Java 动态代理必须要求一个接口的多余限制。旨在使得编程模型变得更加简洁。这个路线也是大多数开源软件框架的路线。比如EJB框架,从EJB2.0 必须实现 Home接口和EJB接口,到只需要@Stateless类似的注释即可完成与容器之间的交互。
? ? ? ?不过生命周期框架的核心思想是:对于OO设计和编程,要重视生命周期的设计,以减少多年后软件或者软件服务升级所带来的苦恼,包括减少代码量,减少测试代码。从对象与对象的交互出发,通过生命周期这把标尺来设计一个概念的范围,比如一个类的范围,哪些行为哪些属性应该包含在一个概念当中,对象与对象之间的关系也是通过生命周期这把标尺来衡量。
? ? ? ?至于表达方式,满足产品本身的性质即可。如果是一个很小的软件,也没有很长的维护周期,那么一个状态模式就已经足够好了。对于复杂的软件,包含很多业务对象,甚至有较深的层级关系,对象与对象之间的关系比较复杂,这个时候采用元数据来描述各自的生命周期以及约束,把生命周期相关的工作交给生命周期引擎完成,就是更好的选择。
?
Lifecycle?基于有限状态机的数学模型定义了编程模型。Lifecycle的编程模型有两部分构成:
生命周期元数据包括以下几部分:
? ? ? ?其中生命周期元数据描述部分与POJO部分分离,这使得在一些复杂情况下,生命周期元数据自身的多态性可以增加重用能力。而POJO部分并不需要编写额外的代码。只是需要通过Annotation指明Lifecycle Engine需要的状态指示器、转移方法、条件转移、关系对象Getter、生命周期回调方法。
?
@StateMachine protected static interface CustomerLifecycleMeta { @StateSet static interface States { @Initial @Function(transition = CustomerLifecycleMeta.Transitions.Activate.class, value = { Active.class }) static interface Draft {} @Functions({ @Function(transition = CustomerLifecycleMeta.Transitions.Suspend.class, value = Suspended.class), @Function(transition = CustomerLifecycleMeta.Transitions.Cancel.class, value = Canceled.class) }) static interface Active {} @Function(transition = CustomerLifecycleMeta.Transitions.Resume.class, value = Active.class) static interface Suspended {} @End static interface Canceled {} } @TransitionSet static interface Transitions { static interface Activate {} static interface Suspend {} static interface Resume {} static interface Cancel {} } }
??
? ? ? 如上述代码片段中,描述了一个简单业务对象的生命周期元数据,它仅包括了状态集合States以及转移集合Transitions。其中状态集合中包含了Draft, Active, Suspended, Canceled四个状态,其中Draft是初始状态(通过@Initial标注),Canceled是最终状态或终结状态(通过@End标注)。转移集合中包含了Activate, Suspend, Resume以及Cancel四个转移。状态与转移之间的关系通过@Function刻画,如下段代码中的@Function用来描述,当对象处于Draft状态上,转移Activate可以将对象变换到Active状态;而其他转移对于Draft状态是无效的。
?
@Initial @Function(transition = CustomerLifecycleMeta.Transitions.Activate.class, value = { Active.class }) static interface Draft {}?
POJO部分代码如下:
public abstract static class ReactiveObject { @StateIndicator private String state = null; protected void initialState(String stateName) { if ( null == state ) { this.state = stateName; } else { throw new IllegalStateException("Cannot call initialState method after state had been intialized."); } } public String getState() { return state; } }?
@LifecycleMeta(CustomerLifecycleMeta.class) public static class Customer extends ReactiveObject { protected Customer() { initialState(Draft.class.getSimpleName()); } @Transition public Customer activate() { return new Customer(); } @Transition public void suspend() {} @Transition public void resume() {} @Transition public void cancel() {} }?
? ? ? ?对于这个简单POJO,即使没有生命周期框架的支持,上面代码片段中的四个业务方法以及对状态属性赋予初始值还是要写的,除此以外还要定义状态模式的四个状态类,然后以紧耦合的方式将状态模式的processMessage方法与四个业务方法联系到一起。而有了生命周期框架的支持,在定义了状态属性以及四个业务方法以后,仅需要对其进行标注。其中@StateIndicator用来指明LifecycleEngine从哪里读取当前业务对象的状态或向哪里写入新的状态。@Transition用来表明某个方法是一个转移方法,可以通过@Transition(Cancel.class)来对应生命周期元数据中的Cancel转移,也可以通过方法名称cancel首字母大写后与Cancel类的SimpleName相匹配。
?
? ? ? ?
? ? ? ?在实际的设计与编程实践中,可以由偏向设计职能的同事完成生命周期的设计并产生生命周期描述元数据,由偏向业务逻辑编写职能的同事完成业务代码的编写。这使得生命周期设计本身与源代码的生命周期始终保持一致,因为元数据本身就是代表了生命周期的设计。任何情况下对业务对象生命周期的调整都必须修改生命周期元数据描述,这也使得只要通过生命周期元数据描述,就可以确切的知道当前业务对象的生命周期的设计。而相对于经典的状态机设计模式,生命周期元数据描述更具表达能力,更简洁清晰。省去了必须在processMessage方法控制结构中返回下一个状态的表达约束。
? ? ? ?除此以外,生命周期引擎还提供状态校验,转移校验,关系约束校验,条件转移,新状态设置,生命周期回调,生命周期事件传播,可插拔的并发锁控制等功能。
?
更多示例代码:
?