动作和变量上下文

1. 动作是可以执行的程序

    现在我们知道了XWorker是一个动态系统,事物可以转化为动作,动作是可以执行的。但是动作是怎样执行的呢?任何一个事物转化后的动作都能正确执行么?本文将回答这些问题。

2. 基本动作:JavaAction

    如果一个动作的事物名是JavaAction,那么它就是基本动作,基本动作是由X-Meta引擎直接解释执行的。

2.1 JavaAction动作模型示例

    如上图是一个JavaAction的示例,在这个模型里指定了Java的类全名和要执行的方法,这样X-Meta引擎就知道要找那个类执行那个方法了。

2.2 JavaAction的Java代码示例

package xworker.swt.widgets;

public class ShellCreator{
     //X-Meta引擎能够调用的方法必须是静态方法,且参数固定为ActionContext
     public static Object create(ActionContext actionContext){
            //相关代码
     }
}

   如上面代码示例,X-Meta引擎调用静态的且参数必须是ActionContext的方法,如果JavaAction指定了合适的类和方法,那么X-Meta引擎就可以正确调用了。

3 变量上下文ActionContext

    在JavaAction的Java代码里我们看到方法的参数是ActionContext,ActionContext的名称叫做变量上下文(或动作上下文),它的主要作用是保存变量用的。

3.1 变量上下文的基本用法

//变量上文的基本用法是保存变量和获取变量

//保存变量
actionContext.put("varName", varObject);

//获取变量
Object varObject = actionContext.get('varName");

3.2 变量上下文也是一个栈

//变量上下文本身也是一个栈,栈中的每一个层是Bindings对象,Bindings可以保存变量

//压栈
Bindings bindings = actionContext.push();

//顶端的栈
Bindings bindings = actionContext.peek();

//出栈
Bindings bindings = actionContext.pop();

//使用Bindings设置变量和获取变量的值
bindings.put("varName", varObject);

Object varObject = bindings.get("varName");

3.3 变量上下文的取值和赋值是自上而下的

    变量上下文是一个栈,从变量上下文取参数时是自上而下获取的,也就是说如果不同的栈层的Bindings包含同样的变量名,那么只会取到顶端第一个包含变量名的那个栈层的变量。

//压入第一个栈
Bindings bindings1 = actionContext.push();
bindings1.put("name", "tom");

//压入第二个栈
Bindings bindings2 = actionContext.push();
bindings2.put("name", "Smith");

//此时控制输出的是顶端栈中的Smith
System.out.println(actionContext.get("name"));

//弹出顶端的栈
actionContext.pop();

//此时控制台输出的tom
System.out.println(actionContext.get("name"));

3.4 使用变量上下文传递参数

    使用变量上下文是一个栈和取变量的自上而下的特性,可以在调用一个动作前压入一个栈,在这个栈中存放参数变量,从而实现传递参数的功能。

3.5 线程安全

    变量上下文的栈是ThreadLocal的,即每个线程拥有一个独立栈,因此变量上下文是线程安全的,变量上下的栈是由各自的线程维护的。

3.6 全局变量和局部变量

    变量上下文的0层栈是每个线程都共有的,因此0层栈的变量相对来说是全局的,而非0层的栈则可以认为是局部的。

4 调用动作

    动作是可以执行的程序,可以在代码中调用动作。由于X-Meta引擎是使用Java编写的,所以可以在Java代码中调用动作。

4.1 调用动作的一般方法

//获取模型事物,其中World是管理事物的容器类,path是事物的路径
Thing thing = World.getInstance().getThing("path");

//转化为动作,任何事物都可以转化为动作
Action action = thing.getAction();

//创建变量上下文
ActionContext actionContext = new ActionContext();

//执行动作
action.run(actionContext);

4.2 通过事物的行为来调用动作

    在用对象的角度看待事物时,事物是具有行为的,调用事物行为的示例如下。

//获取模型事物,其中World是管理事物的容器类,path是事物的路径
Thing thing = World.getInstance().getThing("path");

//创建变量上下文
ActionContext actionContext = new ActionContext();

//执行事物的行为run
thing.doAction("run", actionContext);

    可以看到事物的行为是通过doAction方法调用的。

4.3 动作和行为的差别

    首先行为也是动作,只是一个动作被当成了某个对象的行为,其次行为是通过模型寻找到的某个子模型,最后在代表行为的子模型转化为动作执行前,最为对象的模型本身会以名为self的参数放到变量上下文中。

    所以动作执行时没有self参数,而行为执行时是有self参数的,这里self变量类似Java的this变量的效果。

5 其他非基本类型的动作

    JavaAction是基本类型的动作,但JavaAction也有一点缺陷,那就是Java代码通常是模型之外东西,就算在JavaAction模型中直接写Java代码,那么也是很繁琐的。

    基于以上原因,我们利用事物的行为来实现脚本动作或其它非JavaAction的动作。

5.1 非JavaAction的动作实现原理

    首先在模型编程中动作本身也是模型,因此动作也可以当做对象来看待,如果把动作当做对象来看待,那么动作就具有行为,此时就可以把对象名为run的行为当成它的执行动作了。

    这有点类似java.lang.Runnable这个类,动作是可以执行的,只要实现它的run方法就可以了。

5.2 GroovyAction
     GroovyAction是一个脚本动作,使用它可以直接编写Groovy脚本,能够快速编写动作的代码。

    如上图是GroovyAction的示例,在GroovyAction里脚本是直接写到代码里的。

5.3 其他动作

    通过实现事物的run方法,可以实现各种类型的动作,比如支持Jython、Lua等其他语言的动作,也比如Begin、If、while、for这样的控制语句的动作,也可以实现其它效果的动作。

 

Copyright ©  2007-2019 XWorker.org  版权所有  沪ICP备08000575号