动态模型编程实际上是一种面向对象的编程方法,但由于动态模型编程认为类也是对象,所以在动态模型编程的基本概念中取消了类和对象的概念,而用描述和事物代替了。
模型是动态模型编程中的基本元素,一个模型是由属性和子节点构成的,它和XML的结构类似,因此可以把模型看作是XML,也可以把一个XML看作是一个模型。
比如下面的XML所表示的内容就是一个模型。
<?xml version="1.0" encoding="utf-8"?> <Shell name="shell" descriptors="xworker.swt.widgets.Shell" text="Hello World" RESIZE="true" width="400" height="300"> <FillLayout name="FillLayout"></FillLayout> <Browser name="browser" url="http://www.xworker.org"></Browser> </Shell>
在动态模型编程中假设任何一个模型都是可以执行的,而模型的执行态就是动作,任何一个模型都可以转化为动作来执行。
XWorker的动态模型引擎是使用Java实现的,下面是动作相关的示意代码。
import org.xmeta.World; import org.xmeta.Thing; import org.xmeta.ActionContet; //World是管理模型的容器 World world = World.getInstance(); //使用World通过模型的路径可以获得模型,模型用Thing这个类表示 Thing thing = world.getThing("xworker.example.action._actions.code.GroovyExample"); //任何模型都可以转化为动作,动作用Action这个类表示 Action action = thing.getAction(); //动作可以执行,其中ActionContext是动作执行时的变量容器 action.run(new ActionContext());
在动态模型编程中一个模型的任何一个子节点都被当成独立的模型,而由于模型可以转化为可执行的动作,所以可以约定一个模型的某些子节点是它的行为的定义,比如在XWorker中约定一个模型的第一个名为actions的子节点下的子节点是它的行为的定义。
<thing name="test"> <actions> <GroovyAction name="run" code="println 'Run'"/> <GroovyAction name="helloWorld" code ="println 'Hello World'"/> </actins> </thing>
如上面的模型定义了两个行为,一个名为run,一个名为helloWorld,在Java代码中执行模型的行为的示意代码如下。
import org.xmeta.World; import org.xmeta.Thing; import org.xmeta.ActionContext; //获取test模型 World world = World.getInstance(); Thing test = world.getThing("test"); //执行run行为 test.doAction("run", new ActionContext()); //执行heloWorld行为 test.doAction("helloWorld", new ActionContext());
模型本身就包含了状态(数据),当它有了行为的时候,那么模型就是一个具有状态和行为的对象了。不过由于动态模型编程认为类也是对象,所以取消了类的概念,进而也取消了对象的概念,这时模型就用事物这个概念来称呼了。
需要注意的是在动态模型编程中并没有真正取消类和对象的概念,类和对象的概念其实只是被隐藏了,它们被分解成了更基本的概念,即动态模型编程中的动作、事物和描述等概念,使用这些基本概念可以描述类和对象的概念。
描述的概念相当于类的概念。在动态模型编程中可以把任意一个模型和任意数量的模型作为一个模型描述,比如存在A、B两个模型,可以把A作为B的描述,也可以把B作为A的描述,如果把A作为B的描述,那么也称A是B的描述者。
描述者的作用:
在动态模型编程中,一个模型可以继承其它模型,在继承中模型不继承属性和子节点,只继承行为。比如存在A和B两个模型,如果B继承A,那么B继承A的行为,但不继承A的属性和子节点。
继承往往使用在描述者的继承上,比如张三是一个人,此时人是张三的描述者,而人可以继承动物,动物又可以继承生物,此时张三就同时有人、动物和生物的行为和属性、子节点的定义。
在动态模型编程中,每一个模型都有一个name属性,用来表示它的名字。一个模型的描述者的名字是这个模型的事物名,比如Zhangsan的描述者是Person,那么Person就是Zhangsan的事物名。
为了能够定位到每一个模型节点,每一个模型节点都有一个不变的标识。通常标识的值和名字一样,但如果同级(作为子节点时)的节点包含相同的名字,那么应该设置标识属性。
<?xml version="1.0" encoding="utf-8"?> <ProjectSet descriptors="xworker.ide.worldExplorer.things.ProjectSet"> <ProjectDir name="xworker_app" _xmeta_id_="XWorker_app" isThingRoot="true"> </ProjectDir> <ProjectDir name="xworker_core" isThingRoot="true"></ProjectDir> </ProjectSet>
如上面的代码中,name="xworker_app"的节点的标识是XWorker_app,其中属性名_xmeta_id_是标识的属性名字,而name="xworker_core"的属性name和标识一样,所以_xmeta_id_属性可以不设置。
任何一个模型的节点都有一个唯一的路径,通过路径可以快速定位到一个模型节点。
路径的规则是<目录>.<模型名>/@<节点标识>/@<节点标识>/....,比如_local.xworker.worldExplorer.ProjectSet/@XWorker_app中,_local.xworker.worldExplorer是目录,即对应文件系统的_local/xworker/worldExplorer/目录,模型代码文件名是ProjectSet.dml,这个路径指向的是一个子节点,子节点的标识是XWorker_app。
一个模型的描述者还是模型,描述者的模型路径存放在模型的descriptors属性中,可以有有多个,如有多个使用英文逗号分割。
一个模型可以继承其它模型,继承的模型路径存放在模型的extends属性中,可以有有多个,如有多个使用英文逗号分割。
一个模型的行为约定定义在第一个事物名为actions的子节点下,比如下面的模型定义了run和helloWorld两个方法。
<thing name="test"> <actions> <GroovyAction name="run" code="println run"/> <GroovyAction name="helloWorld" code ="println helloWOrld"/> </actins> </thing>
动态模型编程是一种解释性的编程方法,这个解释规则如下。
XWorker的动态模型引擎是使用Java实现的,所以初始动作叫做JavaAction。
<?xml version="1.0" encoding="utf-8"?> <JavaAction name="create" descriptors="xworker.lang.actions.JavaAction" outerClassName="xworker.swt.widgets.ShellCreator" methodName="create"> </JavaAction>
JavaAction的主要作用是调用Java的静态方法,如上面的模型代码中调用了类xworker.swt.widgets.ShellCreator的create方法,而ShellCreator的create方法的定义如下。
package xworker.swt.widgets; import org.xmeta.ActionContext; public class ShellCreator{ public static Object create(ActionContext actionContext{ } }
如上面的代码,XWorker的动态模型引擎实现叫做XMeta,它的相关类在org.xmeta包下。JavaAction模型能调用的是public的静态方法,并且参数固定为ActionContext,其中ActionContext是用来保存变量用的。
行为也是动作,只是行为在执行时会把它的所有者(模型)使用self变量名保存到变量上下文中,就像在Java的代码中this代表当前对象,self变量就代表当前执行行为的那个模型。
XWorker的动态模型引擎是使用Java编写的,所以下面用Java代码来演示。
//在XWorker里模型用org.xmeta.Thing来表示 import org.xmeta.Thing; //创建一个新的模型,其中Peson是新模型的描述者的路径 //如果为null使用默认的描述者 Thing zhagnsan = new Thing("Person"); //设置属性 zhangsan.set("name", "Zhangsan"); zhangsan.set("age", 40); //设置模型的编码,使用XML格式存储 zhangsan.getMetadata().setCodeType("dml_xml"); //保存到文件,第一个参数是事物管理的名字(相当于ClassLoader) //第二个是参数是模型的路径,比如保存到/xworker/example.Zhangsan.dml文件 zhangsan.saveAs("_local", "xworker.example.Zhangsan");
上面代码中的模型保存为XML,形式基本如下。
<Person name="Zhangsan" age="40" descriptors="Person"/>
在XWorker中模型通过save或saveAs方法通常是保存到文件或数据库中的,而读取的过程就是从文件或数据库中读取模型的方法。
import org.xmeta.Thing; import org.xmeta.World; //World是管理模型的对象,是单态的 World world = World.getInstance(); //初始化World,如初始化事物管理器(相当于ClassLoader的作用) world.init("path"); 通过模型的路径获取模型 Thing zhangsan = world.getThing("xworker.example.Zhangsan");
//模型的属性保存到Map<String, Object>中,所以可以放Java对象,如: thing.set("name", new Object()); //但在保存时可能存在序列化的问题,所以建议存储基本类型,如String、Int等等 thing.set("name", "Zhangsan"); thing.set("age", 40); //获取属性 Object value = thing.get("name"); //也可以通过类型转化的方法获取,即Xxx getXxx(String key)的方法,如: int age = thing.getInt("age"); double age = thing.getDouble("age");
//添加子节点 Thing parent = new Thing(); Thing child = new Thing(); parent.addChild(child); //获取子节点 List<Thing> childs = parent.getChilds();
import org.xmeta.Thing; import org.xmeta.Action; import org.xmeta.ActionContext; //创建事物模型 Thing thing = new Thing(); //任何模型都可以转化为动作 Action action = thing.getAction(); //动作可以执行,其中ActionContext用于保存动作执行时的变量 Object result = action.run(new ActionContext()); //模型可以包含行为,执行方法是通过行为的名字 Object result = thing.doAction(actionName, new ActionContext());
//设置模型的描述者,通过descriptors属性设置 thing.set("descriptors", "Person"); //一个模型可以有多个描述者,路径使用英文逗号分割 thing.set("descriptors", "Person,Animal"); //设置模型的继承模型,通过extends属性设置 thing.set("extends", "Person"); //一个模型可以有多个继承,路径使用英文逗号分割 thing.set("extends", "Person,Animal");