对于一个需要构建复杂的内存结构,相互之间有复杂的依赖关系的应用,如GUI等,用什么样的开发方法最好?
首先,是个语言选择的问题。
C/C++,以及java这样的语言,是基于命令式的。
命令式的语言,强调的是做事的步骤,先做什么,后做什么。前面的步骤直接影响后面的步骤。这样的语言很容易被理解,却不能创造出简洁、复杂而高效的程序。
对于函数式语言,虽然我了解不多,但是相对于命令式语言,要强很多,特别是在使用懒惰计算的时候,它的优势很明显。
但是,函数式语言对于构造这样复杂的数据结构,还是不够直观。
通常对于GUI这样的应用,我们都使用xml这样的描述文件来描述结构。不过大多数的GUI程序,xml的描述能力仅限于窗口的构造,至于期间的业务关系,则很少涉及。
有感于此,我再考虑一个问题,通常的命令式和函数式语言,通常需要描述出怎么做,而不是描述出是什么。 然而,软件开发中主要的问题是搞清楚是什么,而不是怎么做。
能否有一种方式,通过描述出是什么,它自己就可以明白怎么做,该有多好啊。
联想一下html+css的web语言,它重点就是在描述是什么,至于怎么做,都是浏览器需要关心的事情。但是web的目标、使用范围都太专一了,没有什么通用性。
命令式语言同计算机指令在本质上都是一致的,它们都是图灵等价的,因此可以相互转换。
但是声明式语言却不是这样,它更像人类的思维方式,也不是图灵等价的,因此,声明式语言必须经过命令式语言的建模,才能搭建起来。而这个建模是非常复杂而困难的。
那么,有没有一种方法,将声明式语言进行一层层的推演,将它能够推演到一个最基本的最小的模型,这个模型具有很强的通用性,只依赖于一个简单的统一的模型?它所依赖的这个模型,使用命令式语言一次建模后,成为声明式语言的内在模型,然后由这些内在模型在一步一步的建立起和具体事物相关的模型来呢?
探讨软件的本质,是数据的变换。而数据的变换,则有两个关键点构成:结构-映射。
“结构”是指在软件的运行时刻,数据的构成;
“映射”是指不同数据之间的对应关系。
结构反映的是,数据的包含关系。例如,一个person数据,它包含性别、年龄、姓名、身高等这些具体描述一个人的关系。persion数据分别由性别数据、年龄数据、身高数据和姓名数据构成。
映射反映的是,两个数据或者多个数据之间的关联关系。多个数据可能会映射出一个结果。无论怎样,映射的输入端可以有多个变量,但是输出端只能有一个。如果有多个输出,那么每个输出为一个映射。 甚至不一定有输入,但是一定有输出。
结构-映射描述了系统的结构和关系,但是,这种描述还是静态的。但是,软件是一个动态的过程,CPU不停的执行各种指令,那么,如何让这个系统运动起来呢?
这样的系统,运动起来,依靠的是事件。事件是整个系统的原动力。
事件将驱动映射发生作用,映射可以改变结构,从而引起整个系统的变化。
这个系统,称为结构-映射-事件体系。
结构-映射系统中,有一些特殊的组件,被称为事件源。事件源能够自己产生事件,例如定时器结构、输入输出结构等。事件在传播过程中,会被改造、湮灭、重新产生,从而推动系统的运行。
运行时的内存结构
运行时,数据结构被创造出来,映射则一端链接输入节点,一端则链接输出节点。事件则则指向所关联的映射。
比如,一个界面中,有3个输入框:A,B,C。存在映射:C=A + B。 在运行时,它的内存结构是这样的:
窗口对象是根节点,3个输入框:A, B, C是它的子节点。 映射有两个输入点分别连在A和B上,输出点连在C上。
如果映射是自动映射的,当A或者B的值改变后,C的值将自动改变。
在窗口中增加一个button按钮。button的onclick事件指向映射(C=A+B),同时取消这个映射的自动映射,那么,当button按钮被按下后,那么这个映射将会产生。
在系统中,事件有:外部事件和内部事件。
外部事件包括用户输入以及由于用户输入产生的事件(如click),而内部事件,则是数据结构本身的事件,如数据被创建、移除、数据发生改变等。
内部事件能够让映射自动运行,在很多时候,具备很强的处理能力。但是外部事件则是和用户交互的主要手段。
那么,事件和映射的结合能否满足所有要求?不敢这么说,不过有个方法,就是做一个桥节点,并可以自定义映射函数,将结果映射到这个桥节点上。这个桥对象可以完成各种任务。
除了改变值外,映射还具有创建、增加节点和减少删除节点等作用。
xpath,节点查询语言
xpath查询语言可以用在映射和事件处理上。这样可以分离的创建映射和事件。 甚至可以独立于数据本身的定义。
如何来描述呢?
包括以下部分的描述:
1. 对数据定义描述,它定义了一个数据,这类似class或者struct关键字的行为;同时,它定义了数据的各种约束条件,防止在组合时发生问题。
2. 描述一个具体的数据,描述数据如何组合在一起;
3. 对映射进行定义
4. 描述事件、映射如何组合在一起。
上面的例子
<window>
<editor name="A"/>
<editor name="B"/>
<editor name="C"/>
<button name="button1"/>
<mapping>
button1.onclick : {
C.value = A.value + B.value;
}
</mapping>
</window>