`
barryzhong
  • 浏览: 20174 次
  • 性别: Icon_minigender_1
社区版块
存档分类

传統状态模式编程模型 VS 生命周期框架编程模型

阅读更多

       传统编程模型可以采用最经典的状态模式构建状态机,已达到刻画对象生命周期的目的。在这种编程模型中,为了表达一个状态转移需要应用程序员编写下面类似的代码。

例如在Android开放源代码中的StateMachine.java

Java代码 

    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 }

  

        这种虽然完全可以表达状态机的语义并且对于生命周期的变化也非常容易扩展。但是存在以下几个缺点:

  • 要想观看状态机的全貌,这种表达不是很直观。
  • 状态机描述与业务代码的耦合,导致状态机不能重用,这也是把这个状态作为内置类的一个原因。比如若QuittingState根据不同的Message可以去到不同的State,那么业务代码的逻辑判断必须融合到这个QuitingState当中。这个生命周期部分的描述就不可以给其他对象重用。表达方式抽象程度不够。
  • 没有改变开发实践,未能在开发实践中突出对象生命周期设计的重要性。倘若将生命周期通过元数据的方式描述同时与业务代码分开,那么在开发实践中,生命周期的设计工作可以跟团队中设计能力较强的同事的来进行,而经验不丰富的同事可以来编写一般意义上的计算逻辑或者业务逻辑。若有生命周期上的调整,直接修改的是元数据的部分,而不是业务代码的部分,当然如果计算逻辑需要调整一定要修改业务代码。这样的好处是可以让生命周期元数据部分受到更好的管控。而不是在某一个业务对象的Java文件里的某一行修改。
  • 生命周期回调以及状态变化事件的监听,依然需要采取类似于Observer的方式进行。这也是微妙的控制结构表达的问题。这种编程模型是过去比较流行的,现如今Annotation大行其道,通常为了实现回调功能,过去需要写一个类实现一个接口,而现如今只需要声明一个方法,并添加一个Annotation即可,虽然思想相同,但是表达方式更加的简洁。

       Lifecycle的原型在5年前逐渐的演化,从仅仅通过Hash算法进行Transition(转移)的合法性校验,到使用状态模式在processMessage方法中编写更多的业务逻辑。到使用Java Reflection + 动态代理 来进一步简化编程模型,使用元数据描述生命周期,使得生命周期与业务代码分离。再到现如今的通过 Java Instrument在运行时 或者 编译时修改class字节码,以便去掉Java 动态代理必须要求一个接口的多余限制。旨在使得编程模型变得更加简洁。这个路线也是大多数开源软件框架的路线。比如EJB框架,从EJB2.0 必须实现 Home接口和EJB接口,到只需要@Stateless类似的注释即可完成与容器之间的交互。

       不过生命周期框架的核心思想是:对于OO设计和编程,要重视生命周期的设计,以减少多年后软件或者软件服务升级所带来的苦恼,包括减少代码量,减少测试代码。从对象与对象的交互出发,通过生命周期这把标尺来设计一个概念的范围,比如一个类的范围,哪些行为哪些属性应该包含在一个概念当中,对象与对象之间的关系也是通过生命周期这把标尺来衡量。

       至于表达方式,满足产品本身的性质即可。如果是一个很小的软件,也没有很长的维护周期,那么一个状态模式就已经足够好了。对于复杂的软件,包含很多业务对象,甚至有较深的层级关系,对象与对象之间的关系比较复杂,这个时候采用元数据来描述各自的生命周期以及约束,把生命周期相关的工作交给生命周期引擎完成,就是更好的选择。

 

Lifecycle 基于有限状态机的数学模型定义了编程模型。Lifecycle的编程模型有两部分构成:

  1. 生命周期的元数据描述
  2. POJO

生命周期元数据包括以下几部分:

  1. 状态集合 @StateSet,定义了初始状态@Initial,最终状态@End,其他状态,
  2. 转移集合 @TransitionSet, 定义了生命周期中全部转移
  3. 关系集合 @RelationSet,定义了生命周期关系型约束中需要的全部关系
  4. 条件集合 @ConditionSet,定义了条件转移中的全部条件接口

       其中生命周期元数据描述部分与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相匹配。

 

  1.     @StateIndicator  
  2.     private String state = null;  
  1.     @Transition  
  2.     public void cancel() {} 

       

       在实际的设计与编程实践中,可以由偏向设计职能的同事完成生命周期的设计并产生生命周期描述元数据,由偏向业务逻辑编写职能的同事完成业务代码的编写。这使得生命周期设计本身与源代码的生命周期始终保持一致,因为元数据本身就是代表了生命周期的设计。任何情况下对业务对象生命周期的调整都必须修改生命周期元数据描述,这也使得只要通过生命周期元数据描述,就可以确切的知道当前业务对象的生命周期的设计。而相对于经典的状态机设计模式,生命周期元数据描述更具表达能力,更简洁清晰。省去了必须在processMessage方法控制结构中返回下一个状态的表达约束。

       除此以外,生命周期引擎还提供状态校验,转移校验,关系约束校验,条件转移,新状态设置,生命周期回调,生命周期事件传播,可插拔的并发锁控制等功能。

 

更多示例代码:

 

  • 大小: 104.9 KB
分享到:
评论

相关推荐

    ASP.NET的网页代码模型及生命周期

    ASP.NET WebSite编程模型具有以下特点: q 动态编译该页面,而不用编译整个站点。 q 当一部分页面出现错误不会影响到其他的页面或功能。 q 不需要项目文件,可以把一个目录当作一个Web应用来处理。 总体来说,ASP...

    ASP.NET页面框架 PDF

    在本次讲座中,我们将给大家详细介绍有关ASP.NET页面框架的一些知识,如页面生命周期、页面事件、页面指令、页面编程模型等等。 <br/> 课程讲师: 邵志东 MSDN特邀讲师 北京新科海学校 副总经理 <br...

    嵌入式与实时系统开发:使用UML对象技术框架与模式.part2.

    本书将实时系统、对象建模、快速开发过程以及系统保险性等几个完全分离的学科统一起来,重点介绍了使用统一建模语言进行基于模型的实时系统和嵌入式系统开发以及被称为ROPES的基于风险的迭代开发生命周期。...

    系统开发生命周期模型概述-研究论文

    20世纪上半叶,程序化计算机的使用量变得巨大。 结果,软件编程变得越来越不同和复杂。... 此外还研究了迭代推进技术,我们还将推进生命周期模型与编程设计中两个新兴领域的关联复杂化:编程设计和基于部件的编程推进。

    ASP.NET页面框架 Demo

    在本次讲座中,我们将给大家详细介绍有关ASP.NET页面框架的一些知识,如页面生命周期、页面事件、页面指令、页面编程模型等等。 <br/> 课程讲师: 邵志东 MSDN特邀讲师 北京新科海学校 副总经理 <br...

    ASP.NET页面框架 Video

    在本次讲座中,我们将给大家详细介绍有关ASP.NET页面框架的一些知识,如页面生命周期、页面事件、页面指令、页面编程模型等等。 <br/> 课程讲师: 邵志东 MSDN特邀讲师 北京新科海学校 副总经理 <br...

    OSGi.NET框架 Documentation

    本文档主要针对OSGi.NET模块化框架使用进行了描述 ...6.组件的通信支持:组件间通过面向服务的编程模型来达到组件间通信、调用的目的 7.组件的扩展支持:组件提供了扩展点及其扩展来满足某个组件的扩展性支持

    【SpringBootWeb】-SpringBootWeb框架详解

    尽管Spring框架自身对编程模型没有限制,但其在Java应用中的频繁使用让它备受青睐,以至于后来让它作为EJB(EnterpriseJavaBeans)模型的补充,甚至是替补。Spring框架为开发提供了一系列的解决方案,比如利用控制...

    史上最全 69 道 Spring 面试题和答案

    Spring 框架目标是简化Java企业级应用开发,并通过POJO为基础的编程模型促进良好的编程习惯。 2. 使用Spring框架的好处是什么? • 轻量:Spring 是轻量的,基本的版本大约2MB • 控制反转:Spring通过控制反转实现...

    精通ASP.NET.4.0网络编程 part-2

    第1篇ASP.NET网络开发关键技术第1章ASP.NET网络开发基础(教学视频87分钟)1.1ASP.NET事件模型和页面生命周期1.1.1经典的Web事件处理方法1.1.2ASP.NET服务器控件事件模型1.1.3ASP.NET页面生命周期1.2母版页1.2.1母版页...

    精通ASP.NET.4.0网络编程 part-1

    第1篇ASP.NET网络开发关键技术第1章ASP.NET网络开发基础(教学视频87分钟)1.1ASP.NET事件模型和页面生命周期1.1.1经典的Web事件处理方法1.1.2ASP.NET服务器控件事件模型1.1.3ASP.NET页面生命周期1.2母版页1.2.1母版页...

    领域驱动设计与模式实战

    9.3.2 持久化实体的生命周期所需的特定特性 9.3.3 谨慎处理关系数据库 9.4 分类 9.4.1 领域模型风格 9.4.2 映射工具风格 9.4.3 起点 9.4.4 API焦点 9.4.5 查询语言风格 9.4.6 高级数据库支持 9.4.7 其他功能 9.5 另...

    LabVIEW高级编程与虚拟仪器工程应用

    1.1测控项目的生命周期 1.2系统定义 1.2.1 问题定义 1.2.2可行性研究 1.2.3 需求分析 1.2.4软件原型 1.2.5 文档管理 1.3总体设计 1.3.1硬件结构设计 1.3.2软件结构设计 1.3.3 总体设计说明书 1.4详细设计...

    汪文君高并发编程实战视频资源下载.txt

    │ 高并发编程第二阶段13讲、使用观察者设计模式观察线程的生命周期.mp4 │ 高并发编程第二阶段14讲、单线程执行设计模式,有一个门,始终只能一个人通过-上.mp4 │ 高并发编程第二阶段15讲、单线程执行设计模式...

    开源框架 Spring Gossip

    Spring 提供编程式的交易管理(Programmatic transaction management)与宣告式的交易管理(Declarative transaction management),为不同的交易实作提供了一致的编程模型。 Spring 对交易的支援 JDBC ...

    Spring面试71题与答案

    Spring框架目标是简化Java企业级应用开发,并通过POJO为基础的编程模型促进良好的编程习惯。 2.使用Spring框架的好处是什么?  轻量:Spring是轻量的,基本的版本大约2MB。  控制反转:Spring通过控制反转实现...

    Java并发编程实战

    6.2.4 Executor的生命周期 6.2.5 延迟任务与周期任务 6.3 找出可利用的并行性 6.3.1 示例:串行的页面渲染器 6.3.2 携带结果的任务Callable与Future 6.3.3 示例:使用Future实现页面渲染器 6.3.4 在异构任务...

    Java 并发编程实战

    6.2.4 Executor的生命周期 6.2.5 延迟任务与周期任务 6.3 找出可利用的并行性 6.3.1 示例:串行的页面渲染器 6.3.2 携带结果的任务Callable与Future 6.3.3 示例:使用Future实现页面渲染器 6.3.4 在异构任务...

    [ASP.NET.AJAX编程参考手册(涵盖ASP.NET.3.5及2.0)].(美)霍斯拉维.扫描版.pdf

    第21章 页面生命周期和异步的局部页面呈现 第22章 ASP.NET AJAX客户端PageRequestManager 第23章 异步局部页面呈现:服务器端处理 第24章 异步局部页面呈现:客户端处理 附录A XML脚本 附录B 绑定 附录C 动作 附录D ...

    软件框架设计的艺术

    4.5 一个API的生命周期 56 4.6 逐步改善 60 第二部分 设计实战 第5章 只公开你要公开的内容 67 5.1 方法优于字段 68 5.2 工厂方法优于构造函数 70 5.3 让所有内容都不可更改 71 5.4 避免滥用...

Global site tag (gtag.js) - Google Analytics