zoukankan      html  css  js  c++  java
  • 架构风格:数据流

    本文探讨:

    • 什么是管道过滤器风格(Pipe-and-filter Style)
    • 管道过滤器风格的约束
    • 管道过滤器风格的适用场景
    • 什么是批量顺序处理风格(Batch-sequential Style)
    • 批量顺序处理风格的约束
    • 批量顺序处理风格的适用场景
    • 批量顺序处理与管道过滤器的差异是什么
    • 什么是过程控制风格(Process Control Style)
    • 过程控制处理风格的约束
    • 过程控制处理风格的适用场景

    不论是出国还是看电影,不知道你有没有发现,很多国家的自来水是可以直接喝的,而中国的就不行。你有没有想过,为什么我们国家的自来水不能直接喝呢?而且好像就只有中国人特别喜欢喝热水!感冒、咳嗽、不舒服,发烧、流感、大姨妈,只要身体有点什么不舒服了,不管三七二十一,先喝点热水!

    这主要和以前的瘟疫、寄生虫、肠胃炎有关系。以前的水基本没有过滤,寄生虫病菌比较多,经常引起各种疾病,所以很多国家都对水进行了净化处理,能达到直接喝的标准。而以前我们国家还没有能力做这种净化处理,但是发现水烧开了也可以有效的杀死这些细菌,所以喝热水的传统就这么延续下来了。

    对水的净化处理其实原理很简单,就是「过滤」!如果你家里安装过净化水系统,应该会发现净化器一般都会有几个过滤器,一般是三个。作用就是自来水经过一个个的过滤器,去除了水中的各种杂质,能达到直接饮用的程度。其中,每一个过滤器都是独立的,可以独立的替换。

    数据流风格就是类似的处理方式,将数据看做水,一个个的处理单元看过一层层的过滤,数据经过一个个的处理单元,最终达到我们需要的结果。

    说到过滤器,我们的第一印象应该就是Web开发中遇到的「过滤器/拦截器」了,继而想到的应该就是设计模式中的职责链模式。

    所以我们就从我们熟悉的职责链模式开始,来聊聊「数据流风格」。

    职责链模式

    职责链的类图如下:

    从结构上看,职责链模式有两个对象:Client和Handler(包括具体的Handler实现)

    • Client发送消息给Handler
    • Handler将消息委托给具体的Handler链条处理
    • 处理完成后,返回给Client

    Handler的具体实现就是一个个的过滤器,独立的处理数据,也可以独立的替换,这就解耦了请求发送者和接收者。请求沿着Handler链条依次传递,每个Handler判断是否需要处理该请求,直到所有Handler都处理完成为止。

    职责链主要适用于如下场景:

    • 有多个对象可以处理一个请求,但是哪个对象处理该请求需要运行时自动确定
    • 需要在不明确指定接收者的情况下,向多个对象中的一个提交一个请求
    • 可处理一个请求的对象集合是动态指定的

    下面是一个简单的clojure例子:

    (defn handler-request1 [condition]
        (if (= "ConcreteHandler1" condition)
            (println "ConcreteHandler1 handled ")
            (println "ConcreteHandler1 passed ")))
    
    (defn handler-request2 [condition]
        (if (= "ConcreteHandler2" condition)
            (println "ConcreteHandler2 handled ")
            (println "ConcreteHandler2 passed ")))
    
    (defn handler-requestn [condition]
        (println "ConcreteHandlern handled "))
    
    (->> "ConcreteHandler2"
        handler-request1
        handler-request2
        handler-requestn)
    ;handler-request2和handler-requestn会处理此字符串
    

    管道过滤器风格

    管道过滤器风格和职责链模式在结构上比较类似。管道过滤器风格包含了四个组件:

    • 读端口:用于读取数据,如标准输入流、文本文件或传感器采集的数据等。类似职责链的Client发送消息。
    • 写端口:用于写出数据,如文本文件、数据库、标准输出等。类似职责链的Client接收处理完的消息。
    • 管道:用于连接各个过滤器,使得消息能在各个过滤器之间进行流转,也包含数据缓冲作用。类似职责链里的调用(消息发送)
    • 过滤器:处理消息组件,过滤器可以通过pull(后续过滤器从当前过滤器中拉取数据),push(前面的过滤器向当前过滤器推送数据)或主动方式(不断从前面的过滤器中拉取数据,并向后面的过滤器推送数据)来获取消息。类似职责链模式里的Handler。

    管道过滤器风格的完整流程为:「读端口」获取需要处理的信息,通过管道传递给过滤器链,每个过滤器自行判断是否需要对信息进行处理,一个过滤器处理完后通过管道将消息传递给下一个或多个过滤器,直到所有的过滤器全部处理完毕,通过写端口,将处理完成的信息写出到目标位置。

    管道过滤器风格的典型应用有:

    • Linux的Shell
    • JavaEE Servlet Filter
    • 传统的编译器:一个阶段(包括词法分析、语法分析、语义分析和代码生成)的输出是另一个阶段的输入。

    以Linux的Shell为例:

    cat "app.log" | grep "^error" | cut -f 2
    
    • cat指令获取app.log的内容,将结果通过管道传递给grep
    • grep指令过滤出所有以error开头的行,将结果通过管道传递给cut
    • cut取出第二列的内容

    在这里cat,grep,cut就是一个个的过滤器;而 | 就是管道;输入输出则是标准输入输出。

    管道过滤器风格将处理逻辑封装到独立的过滤器中:

    • 可以通过新增过滤器的方式增加对信息的处理逻辑,相反可以通过移除过滤器的方式减少对信息的处理逻辑。提高了系统的扩展性
    • 过滤器之间没有逻辑上的关联关系,提高了复用性
    • 同时易于增加过滤器和移除过滤器,提高了系统的可维护性
    • 但是每个过滤器需要对信息进行解析,降低了系统性能,以及增加了过滤器自身的复杂度
    • 不过过滤器可以并行执行,这可以提高系统性能

    管道过滤器风格主要用于处理数据的系统,不适用于处理交互的应用。

    批量顺序处理风格

    同样的「批量顺序处理风格」也是主要用于处理数据的架构风格。一般它的处理组件称为阶段(stages)或者步骤(steps)。

    它的处理流程如下:

    • 读取一批数据,进行处理
    • 信息不是通过所谓的「管道」在各个阶段之间进行流转,而是通过类似临时中间文件来进行阶段之间的流转,而文件可以被删除
    • 下一阶段需要在前一阶段处理完后才能执行
    • 下一阶段会从前一阶段处理后的文件里,选择自己需要的文件进行处理,处理后再写到文件中

    批量顺序处理风格的每一步处理都是独立的,并且每一步是顺序执行的。只有当前一步处理完,后一步处理才能开始。数据传达在每一步处理之间作为一个整体。比较适用于需要顺序执行的某些固定操作的场景,并且这种流程不经常进行变化。Windows下的BAT程序就是这种应用的典型实例。

    批量顺序处理风格对架构属性的影响与管道过滤器基本一致,这里不再赘述。

    管道过滤器与批量顺序处理差异

    两种风格都包含一系列的计算组件,通过将数据交给这一系列的计算组件来处理,来完成任务。

    两种风格的不同之处在:

    管道过滤器风格 批量顺序处理风格
    细粒度 粗粒度
    结果驱动处理 高延迟
    内部输入 外部访问输入
    可以并发 不支持并发
    交互不友好 不支持交互

    内部输入:过滤器之间直接传递数据
    外部访问输入:批量顺序处理一般都会先输出到一个临时文件,下一个阶段再从临时文件中获取

    过程控制风格

    过程控制风格和上面的两个风格处理方式差异较大,一般应用在嵌入式开发中,包含了四个组件:

    • 传感器(Sensor):监听某些重要信息
    • 控制器(Controller):逻辑控制
    • 执行器(Actuator):操作过程的物理方法
    • 过程(Process):你想要控制的内容

    空调使用的就是过程控制风格,如下图:

    • 我们打开空调,设置了21度
    • 空调的温度传感器(Sensor)检测到室内温度(Process)为15度,温差为6度
    • 控制器(Controller)控制执行器(Actuator)吹热风
    • 当室内温度达到21度后,传感器就通知控制器控制执行器停止工作

    过程控制风格将系统拆分为一个个的子系统或模块:

    • 各个子系统或模块相互独立,提高了模块的复用性,以及系统的进化性可维护性
    • 子系统或模块间的交互可能会影响性能

    参考资料

  • 相关阅读:
    用纹理贴图模拟反射,NeHe23课球面映射相关
    VS2010: CommandLine Warning D9025
    【转】C RunTime Library 暨 深入理解编译选项的含义 01
    让Doxygen输出中文注释不乱码
    windows环境下memcache配置
    C#中英文字符长度截取
    apache 的工作原理
    pear包安装phpunit
    使用 libevent 和 libev 提高网络应用性能
    PHP发明人谈MVC和网站设计架构——貌似他不支持php用mvc
  • 原文地址:https://www.cnblogs.com/ivaneye/p/10263520.html
Copyright © 2011-2022 走看看