流程式编程

流程式编程在许多商业框架中都有实现。

Tiny框架构建者认为,流程式编程与普通的编程式开发,各有其应用场景及优势。

编程式开发,程序员有更大的自由度,当然也正是由于其具有的极大自由度导致项目的进度、质量方面带来了极大的不确定性,同时对于未来的维护方面也可能挖下了巨大的坑。

而流程式编程呢,对于开发人员有了较大的限制,也就是说,只能用已经开发好的组件进行开发,或者扩展自己的组件进行开发。开发过程当然就受限制了,可能在项目初期,会带来一定的开发效率降低,但是最后的维护成本方面会有比较大的节省,当然,其最大的被诟病的就是在实现某些功能的时候,不方便;还有就是程序员认为长时间使用流程编排式开发会降低开发能力,而受到抵制。

正是由于编排式编程在后期维护方面带来的便利,使得流程编排式开发方式存在其实际的生存空间。当然,Tiny框架提供的流程编排式框架,提供了与一般常见流程编排开发方式不一样的特性。

充分支持面向对象特性的流程编排开始模型

首先来从一个简单的示例看起:

?


1

2

3

4

5

6

7

8

9

10

11

12

<flow id="1000" name="Hello">

    <nodes>

        <node id="begin">

            <component name="helloWorldComponent">

                <properties>

                     <property name="name" value="World" />

                     <property name="resultKey" value=""helloInfo"" />

                </properties>

            </component>

        </node>

    </nodes>

</flow>

组件helloWorldComponent的源码如下:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

public class HelloWorldComponent implements ComponentInterface {

    String name;

    String resultKey;

 

    public String getResultKey() {

        return resultKey;

    }

 

    public void setResultKey(String resultKey) {

        this.resultKey = resultKey;

    }

 

    public String getName() {

        return name;

    }

 

    public void setName(String name) {

        this.name = name;

    }

 

    public void execute(Context context) {

        context.put(resultKey, String.format("Hello, %s", name));

    }

 

}

从上面的代码可以看出,其实它的逻辑非常简单。提供了两个自定义属性,一个是name,一个是resultKey,最后在其execute方法中,从其实现逻辑可以看出,它就是把“Hello, ”加上输入的名字,放在了环境变量的resultKey当中,然后返回。

流程组件的接口,也非常简单,如下:

?


1

2

3

4

5

6

7

8

public interface ComponentInterface {

    /**

     * 组件执行方法

     * @param context 组件执行的环境

     */

    void execute(Context context);

 

}

所以,其实现也是非常简单的。

下面是调用此流程的方法:
a.按默认开始结点开始执行

?


1

2

3

Context context = new ContextImpl();

flowExecutor.execute("1000",  context);

assertEquals("Hello, luoguo", context.get("helloInfo"));

b.从指定节点开始执行 

?


1

2

3

Context context = new ContextImpl();

flowExecutor.execute("1000","begin", context);

assertEquals("Hello, luoguo", context.get("helloInfo"));

可以看到确实是执行并返回了结果,但是它的执行机理是怎么样的呢?? 
看一个更全面的流程配置: 

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

<flow id="1000" version="1.0" privateContext="false" extend-flow-id="" name="Hello" title="你好示例" default-node-id="end" begin-node-id="begin" end-node-id="end" enable="true">

  <description>some thing....</description>

  <nodes>

    <node id="begin">

      <component name="helloWorldComponent">

        <properties>

          <property name="name" value="&quot;luoguo&quot;"/>

          <property name="resultKey" value="&quot;helloInfo&quot;"/>

        </properties>

      </component>

      <next-nodes>

        <next-node component-result="OK" exception-type="java.lang.Exception" next-node-id="end"/>

      </next-nodes>

    </node>

  </nodes>

</flow>

其中flow节点的属性含义为: 
id,唯一确定一个流程 
privateContext,如果是true,则在流程单独申请一个context,否则共用调用者的context,这样可以有效避免环境变量冲突问题 
extend-flow-id,继承的流程id,这个继承id是一个非常强大的功能,后面详细介绍 
version版本号,同一id的流程可以存在多个版本,访问时,如果不指定版本则默认采用最新版本 
name,title仅用于说明其英文,中文名称,易于理解而已。 
default-node-id表示,默认执行节点,即如果一个组件执行完毕,其项值没有指定下一处理节点则执行默认节点 
begin-node-id,开始节点 
end-node-id,结束节点 
如果不指定,则begin-node-id默认为begin,end-node-id默认为end 
node节点:id必须指定,在一个流程当中id必须唯一。 
component节点 
class-name用于指定组织实现类名 
properties是组件的属性列表 
property中的name与value是组件的属性的值,value,这里传入的是个字符串,但是实际当中可以处理中可以非常灵活,后面再介绍。 
next-nodes,是指根据执行结果进行后续处理的规则。 
next-node,具体的一条规则,component-result,匹配项,支持正则表达式,节点中的组件执行结果进行匹配,匹配成功则执行此规则中的下一节点。 
exception-type是异常的类名称,如果出现异常且与这里定义的类型匹配,则执行此规则中的下一节点。 
关于继承

上次说到继承,流程继承实现起来是非常简单的,只要在extend-flow-id属性中指定即可。
继承不支持多继承,即流程只能继承自一个流程,但是可以支持多层继承,即
a>b>c>d.....
实际开发过程中,不要把继承搞得太复杂,这样会把程序逻辑搞得更难理解的。
继承实际会起到什么作用呢?
首先,会继承一些属性,另外会把节点信息继承过来。
简单来说就是:两者都有,当前流程说了算,当前没有,父流程说了算。
继承应用到什么场景呢??
继承应用于业务处理的模式非常相似,只有中间处理环境不同的时候。
比如:
A  B  C  D ---O--- -D -C -B -A
类型的业务处理流程,只有O不同,其他处理模式完全相同,此时采用继承方式都非常舒服了,
只要定义父流程,在子流程中只用定义O一个流程节点即可。以后要统一进行流程调整,只要在父流程中进行调整就可以了。
比如:flow aa定义为:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

<flow id="aa" name="aa">

  <nodes>

    <node id="begin">

      <next-nodes>

        <next-node component-result="begin" next-node-id="hello"/>

      </next-nodes>

    </node>

    <node id="hello">

      <component name="helloWorldComponent">

        <properties>

          <property name="name" value=""luoguo""/>

          <property name="resultKey" value=""helloInfo""/>

        </properties>

      </component>

      <next-nodes>

        <next-node component-result="OK" next-node-id="end"/>

      </next-nodes>

    </node>

  </nodes>

</flow>

flow bb定义为:

?


1

2

3

4

5

6

7

8

9

10

11

12

<flow id="bb" name="bb" extend-flow-id="aa">

    <nodes>

        <node id="hello">

            <component name="helloWorldComponent">

                <properties>

                    <property name="name" value="LG" />

                    <property name="resultKey" value=""helloInfo"" />

                </properties>

            </component>

        </node>

    </nodes>

</flow>

则流程bb也可以顺利执行,且执行结果是Hello, LG

流程的可重入性:

一般的流程编排引擎中,流程是不可重入的,也就是一个流程一定是从开始节点起执行,一定执行到结束结点结束。在Tiny流程引擎中,不仅可以在当前流程中进行切换与转接,还可以流转到其他流程的节点当中,这在业务处理及页面处理,流程处理方面都提供了极大的使得,但是这也是一个双刃剑,在提供了这么灵活的功能的同时,也会导致业务流程看起来比较复杂,因此,控制方面最好由架构师或核心开发人员来编写,普通开发人员只开发具体的业务点即可。
小结

Tiny框架提供的流程编排引擎,功能强大,扩展灵活,支持了部分面向对象的特性,比如继承、比如重载,再加上流程的可重入性,使得它更加灵活,便捷。当然,流程编排式编程还有一个非常强大的功能,就是可以进行在线式编程,Xml式流程配置完毕,马上就可以执行出结果。

时间: 2024-10-17 15:19:42

流程式编程的相关文章

《挖掘管理价值:企业软件项目管理实战》一第 2 章 流程式生产软件——过程管理

第 2 章 流程式生产软件--过程管理 挖掘管理价值:企业软件项目管理实战 做事需要章法,管理需要流程.软件开发生命周期理论定义了软件开发普遍的过程,软件项目管理工作之一就是以此为基础,对软件开发的过程进行细致的管理. 本章重点 建立项目流程.为了标准化软件开发的过程,企业应该根据自己的管理要求建立项目管理流程. 项目确立过程.要开始一个软件项目,就必须先对项目的合理性进行恰当的论证和评估. 需求分析过程.软件的内容和功能来源于需求的收集和分析,应该根据需求的重要性来设定开发的优先级. 软件设计

《面向对象的思考过程(原书第4版)》一1.3 过程式编程与面向对象编程

本节书摘来自华章出版社<面向对象的思考过程(原书第4版)>一书中的第1章,第1.3节,[美] 马特·魏斯费尔德(Matt Weisfeld) 著黄博文 译更多章节内容可以访问"华章计算机"公众号查看. 1.3 过程式编程与面向对象编程 在我们深入了解面向对象开发的优势之前,先考虑一个更基本的问题:究竟什么是对象?这既是一个复杂的问题,也是一个简单的问题.它复杂是因为学习任何一种软件开发方法论都非易事.它简单是因为人们已经在按对象的方式进行思考.例如,当你看到一个人,你会把他

Java中基本数据类型与流_JSP编程

Java中除了二进制文件和使用文本文件外还有基于Data的数据操作,这里的Data指的是Java的基本数据类型和String.基本数据类型包括byte.int.char.long.float.double.boolean和short. 说到Java的基本数据类型必须谈到的两个类是DataInputStream和DataOutputStream.它们提供了对Java基本数据类型的操作,但是这些方法事实上是在两个重要的接口中定义的DataInput和DataOutput,它们的功能就是把二进制的字节

使用TinySpider实战抓取自己博客中的内容

因为做官网,没有内容,因此就想办法从OSChina中写的博客里弄点内容,这就要用到爬虫了. 然后就花了几分钟搞了一下,步骤如下: 第一步,写个方法抓目录: ? 1 2 3 4 5 6 7 8 9 10 11 public static void processCategory(String categoryId) {         Watcher watcher = new WatcherImpl();         Spider spider = new SpiderImpl();    

泛函编程(24)-泛函数据类型-Monad, monadic programming

   在上一节我们介绍了Monad.我们知道Monad是一个高度概括的抽象模型.好像创造Monad的目的是为了抽取各种数据类型的共性组件函数汇集成一套组件库从而避免重复编码.这些能对什么是Monad提供一个明确的答案吗?我们先从上节设计的Monad组件库中的一些基本函数来加深一点对Monad的了解: 1 trait Monad[M[_]] extends Functor[M] { 2 def unit[A](a: A): M[A] 3 def flatMap[A,B](ma: M[A])(f:

《JavaScript应用程序设计》一一2.13 链式调用与流式API

2.13 链式调用与流式API 链式调用是指下一次方法调用的上下文环境,由前一次方法调用的输出结果提供,下面的代码实例在jQuery中较为常见: $('.friend').hide().filter('.active').show(); 更为清晰的写法: $('.friend') .hide() .filter('.active') .show(); 这一连串方法调用的内在含义为: 先找出所有类名为.friend的元素并将它们隐藏,随后在其中找出所有拥有.active类名的元素并将之显示. 在页

最大限制地提高代码的可重用性,克服传统面向对象编程方法在可重用性方面的不足

编程|对象     重用是一种神话,这似乎正在日渐成为编程人员的一种共识.然而,重用可能难以实现,因为传统面向对象编程方法在可重用性方面存在一些不足.本技巧说明了组成支持重用的一种不同方法的三个步骤. 第一步:将功能移出类实例方法由于类继承机制缺乏精确性,因此对于代码重用来说它并不是一种最理想的机制.也就是说,如果您要重用某个类的单个方法,就必须继承该类的其他方法以及数据成员.这种累赘不必要地将要重用此方法的代码复杂化了.继承类对其父类的依赖性引入了额外的复杂性:对父类的更改会影响子类:当更改父

Node.js中的流(Stream)介绍

 这篇文章主要介绍了Node.js中的流(Stream)介绍,本文讲解了什么是流.pipe方法.流的分类.Readable流状态的切换等内容,需要的朋友可以参考下     什么是流? 说到流,就涉及到一个*nix的概念:管道--在*nix中,流在Shell中被实现为可以通过 |(管道符) 进行桥接的数据,一个进程的输出(stdout)可被直接作为下一个进程的输入(stdin). 在Node中,流(Stream)的概念与之类似,代表一种数据流可供桥接的能力. pipe 流化的精髓在于 .pipe(

函数式编程入门教程

你可能听说过函数式编程(Functional programming),甚至已经使用了一段时间. 但是,你能说清楚,它到底是什么吗? 网上搜索一下,你会轻松找到好多答案. 与面向对象编程(Object-oriented programming)和过程式编程(Procedural programming)并列的编程范式. 最主要的特征是,函数是第一等公民. 强调将计算过程分解成可复用的函数,典型例子就是map方法和reduce方法组合而成 MapReduce 算法. 只有纯的.没有副作用的函数,才