日期:2014-05-16  浏览次数:20388 次

JavaScript动作迁移器

?

1.?设计背景

JavaScript动作迁移器来源于这样的环境:某个操作因为代码复用和增强其内聚性而被分为几个单独的动作(函数),这些动作中在逻辑上存在先后关系,即前一个动作完成后才能继续下一个动作,但是某些动作却是异步的(asynchronous),这样在编码过程中就不能按过程调用的方式来编写,必须将异步动作的下一个动作放到该异步动作中,这种调用方式,在代码量很小,其逻辑不是很复杂的情况下,还是可以的,但是当异步动作中代码量较大且逻辑复杂的情况下,会增加函数的耦合度,降低代码的阅读性,加大代码维护的难度。

为了减少代码的耦合,是逻辑更加清晰,于是设计产生了动作迁移器。使用动作迁移器,所有的动作都将在操作开始前进行定义,操作开始后,就将按照定义的动作序列调用各个动作。并且,每个动作可按照其运行的状态调用其他不同的动作或是内部不同的状态。

2.?术语解释

首先,解释一下该动作迁移器所涉及到的术语的含义:

动作迁移器(ActionTransfer),维护的是一系列动作的执行路线,使动作能够按照指定的迁移路径运行下去。

动作(Action),指的是一个确定的完整的执行过程,而不是执行片段,如判断是否为真之类的,该动作完成后没有后续的与该操作处理相关的过程,但其可以有执行后得到的数据,该数据可以被后续动作继续使用。

迁移路径(TransferPath),即一个动作到下一个动作的运行线路,它规定了某个动作执行完后,其后续所要执行的动作,或是该动作的完结。每个动作都可以有执行状态,可以从动作的某个状态迁移到另一个动作,或另一个动作的某个状态,也可以是某个动作的不同状态间的转移。

动作状态(简称状态,Status),即某个动作运行完毕后,可以通过状态指示其执行是成功还是失败或是出现异常等,动作迁移器可以根据其执行状态,沿着迁移路径继续进行处理。

动作的迁移可以是没有起点的,也可以有多个起点,动作迁移器不需从起点开始迁移,可以从任何一个动作开始迁移,开始迁移后,其迁移的路径是按照指定的路径运行下去,直到该条路径的终点(即没有下一个迁移动作)。

3.?功能结构

该动作迁移器内置的属性有当前动作(action)、初始动作(initAction)、和迁移路径(transferPath),并设方法start(启动初始动作)、setAction(设置当前迁移动作)、transfer(根据动作状态进行指定的迁移操作)、clear(清除迁移路径)。详细设计代码如下:

?

ActionTransfer = Ext.extend(Object, {  
    action : 'start'  
    , constructor : function(config, scope) {  
        var conf = config || {};  
          
        this.scope = scope || this;  
        this.initAction = conf.initAction || 'start';  
        // 迁移路径,包含start和end动作  
        this.transferPath = Ext.applyIf(conf.path || {}, {  
            'start' : function() {},  
            'end' : function() {}  
        });  
          
        if (conf.auto === true) {  
            this.start();  
        }  
    }  
    /** 
     * 启动迁移 
     * @return {ActionTransfer} this 
     */  
    , start : function() {  
        return this.setAction(this.initAction).transfer();  
    }  
    /** 
     * 设置当前动作 
     * @param {String} action the current action's name 
     * @param {Function} fn the function will be called, after setting action 
     * @return {ActionTransfer} this 
     */  
    , setAction : function(action, fn) {  
        if (!this.transferPath) {  
            alert('ActionTransfer : no defined route chain');  
        } else if (action && action != ''  
                              && this.transferPath[action]) {  
            this.action = action;  
            if (typeof fn == 'function') {  
                fn.apply(this.scope);  
            }  
        } else {