• 2004-03-08

    模拟语法结构

    Tag:向上走

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://www.blogbus.com/dreamhead-logs/115466.html

    项目组的一个兄弟提出一个令我目瞪口呆的想法,模拟语法结构。

    实际做法很简单,下面以Java语言讲解一番。

    学过编程语言的都知道,语句是程序设计中的一个基本单位,大语句由小语句组成。

    我们定义语句如下:
    public interface Statement {
        public void execute(Context context) throws Exception;   
    }

    其中context是用来存放执行语句所需的相关信息的一个接口。

    一旦看到了语句的出现,我们很自然就会联想到顺序语句、选择语句和循环语句等等,这几种语句也是语句,看起来这是废话,实际上我指的是LSP(Liskov替换原则)。所以,我们让这几种语句也成为语句,下面给出一种可能的顺序语句实现:
    public final class Sequence implements Statement {
        private Statement[] statements; 

        public Sequence(final Statement[] statements) {
            this.statements = statements;
        }

        public void setStatements(final Statement[] statements) {
            this.statements = statements;
        }

        public void execute(Context context) throws Exception {
            for (int i = 0; i < this.statements.length; i++) {
                this.statements[i].execute(context);
            }
        }
    }

    结构很简单,顺序语句由一堆“语句”组成,execute就是顺序调用就OK了。
    我们可以用同样的方法实现选择语句、循环语句。

    到这里,我们可能还无法看出这种结构的优点:语言已经提供了很好的结构,为什么要模拟?
    这么做最吸引我的地方就在于它的可配置性。

    IoC,Robert Martin叫它DIP,对了,Martin Flower给它改了个名叫Dependency Injection,最近比较火爆,《程序员》2004年第三期上有一篇gigix翻译Martin Flower的那篇《Inversion of Control Containers and the Dependency Injection pattern》比较详细的讨论了它。

    稍微对它熟悉一点的话,我们不难看出,上面Sequence的实现用到了setter和constructor,它们分别代表了IoC的type 2和type 3,通过这种方式,我们就可以很轻松的配置自己的应用了。

    我知道这么说,还会让人有一头雾水的感觉。

    我们应用的新版本是在SpringFramework的基础上构建起来的,SpringFramework就是一个很好的IoC容器。它让我们可以通过配置文件来构建整个应用。
    假设BasicProcessor1和BasicProcessor2是两个实现了Statement接口的类。使用SpringFramework,我们可以这样构建自己的应用。
    <bean id="processor1" class="BasicProcessor1">
    <bean id="processor2" class="BasicProcessor2">

    <bean id="flow" class="Sequence">
        <property name="statements">
            <ref bean="processor1"/>
            <ref bean="processor2"/>
        </property>
    </bean>

    其中,processor1和processor2可以分别看作BasicProcessor1和BasicProcessor2的instance。flow是Sequence的一个instance。

    当系统生成时,SpringFramework会自动调用setStatements将processor1和processor2作为一个数组设置到flow中去。这样就省去了我们手工配置系统的繁琐工作。
    说起来很神奇,其实这是利用了JavaBean的一些特性。

    回到我们前面的讨论上。
    当这种配置方法和模拟语法结构相结合,威力就显现出来了。
    我们完全可以在不改动系统源代码的情况下,修改系统生成的配置文件,从而达到改变流程的目的。
    如果有了新的需求,我们可以单独开发一个Statement,然后再把它配置到系统中,而原有的代码无需任何改动。
    多么美妙的一种想法啊!

    放任我们的思绪继续前行!
    真正控制我们应用结构的是我们的配置文件。在SpringFramework中,在一个应用中可以有多个配置文件,我们可以把组件定义放在一起,而把流程控制的部分放在一起。于是,我们只要修改流程控制的部分就可以达到对整个系统的重新设定。
    前面已经说过,模拟语法结构无非是顺序语句、选择语句、循环语句等等,从本质上说,它就是一门语言,而我们的流程配置文件就是这种语言的源代码,唯一的缺陷就是相对烦琐一些。
    如果我们再向前迈一步,把模拟的语法结构变成真正的语法结构,那它就会成为一门真正的语言。编译器的工作就是将一种语言转化为另一种语言,而我们流程配置文件本身就是模拟语法结构的源文件。我们完全可以开发一个小型的编译器,将这种语言编译生成我们流程控制文件。
    达到这一步的话,以后的应用开发就成了用这种小语言来编写控制流程,只有真正的新东西才需要我们编写Java代码,这将极大的降低我们开发的工作量。

    或许这会引起某些人的不屑,前面说过模拟语法结构是为了不编译代码,如果开发自己的编译器编译和用Javac编译有什么不同?
    复杂程度。
    二者所在的层次不同,我们用自己的语言控制的流程,而不是细节。
    如果把我们的语言比作高级语言的话,那么直接用Java编写的代码无异于现在的汇编,想必大家对二者的开发速度都有自己的比较吧!

    模拟语法结构,这种做法本身上没有什么技术难度,难的在于把它提炼出来,惯性思维常常会局限我们的思路。

    或许不经意间,又一个好想法浮现于脑海之中。
    不要犹豫,赶快操起键盘实现它!

    分享到:
    引用地址:

    评论

  • 路过,你的文章真好。

    我觉得IBM的WorkFlow(工作流)也许是基于这样的思想实现的。WF中的流程节点(Activity)也许就是你文中的组件定义,而节点间的控制流也许就是流程控制部分,这样WF实现了任意调整流程顺序的功能,也许就是上文思想的一个真实再现。这么一分析,更清晰了,WF的BuildTime简直就是一个IDE开发工具,而生成的.cfg文件就是我们的程序,Fmcibie.EXE就是编译器。

  • 实在是一个好想法,但你的表达更好,佩服佩服!!
    回复jxb8901说:
    多谢你的鼓励,欢迎多多关注梦想风暴。Blogbus恢复正常,梦想风暴也将恢复正常。
    2004-03-26 14:49:04