`
peizhiinfo
  • 浏览: 1424746 次
文章分类
社区版块
存档分类
最新评论

给我一个婚介所,就能搞到一群姑娘! -- mediator(中介者)设计模式的精髓 .

 
阅读更多

引题

今天看了非常给力的《艺龙旅行网架构案例分享http://www.infoq.com/cn/presentations/jzf-elong-architecture-case-study<wbr>,里面提到了mediator模式。 之前在学习设计模式的时候就注意到了这个模式,现在看了里面的几个应用非常受启发。</wbr>

<wbr><wbr><wbr><wbr>mediator 解决的是多个对象之间关系复杂,连线太多的问题。它的目标就是要减少这些连线的数量,降低复杂度!像不像婚介所,本来我要维护一堆姑娘的联系方式,并还要自己一个个的找(她们也是如此维护和众男伴的关系),ok,现在包办给婚介所就好了。</wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr></wbr></wbr></wbr></wbr>所以mediator模式的口号是:

<wbr> “给我一个婚介所,就能搞到一群姑娘!”</wbr>

<wbr></wbr>

入题

<wbr></wbr>

在婚介所我们维护的是男女关系,那么在程序当中我们维护也是关系,画在纸上就是各种各样的“连线”,那么有哪几种连线呢?其实可以套用硬件总线的分类方法,当然首先你得连线的对象是谁,就像知道得找怎样的姑娘一样。

1) 数据: 要给什么?可以细为

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>数据的格式,</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

数据的内容

<wbr></wbr>

2) 控制: 怎么给?可以细为

空间上怎么给 -- 调用关系依赖

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> 时间上怎么给 -- 同步的给,还是异步的等</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr></wbr>

3) 地址: 如何找到她?可以细分

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>地址,她在哪?</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>路由,如何找到她?</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr></wbr>

破题

视频当中使用了 i Spring IoC

ii Canonical Data Format 、

iii SOA Enterprise Service BUS。按照上面的分类可以对号入座。


1)数据

最好理解的是数据,对应视频举例ii。

<wbr><wbr> 几个对象之间传递数据,先转化成统一格式,每个对象接收后在转成自己的格式。</wbr></wbr>

<wbr><wbr><wbr><wbr>而对于数据内容,这个类似于数据同步了,其实就是视频当中第一个配置文件分散、更改麻烦的问题。所以引入了一个中心节点,所有的配置文件都从这个节点上抓取。</wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr>拿婚介所的例子来说,比如婚介所搞了一个网站,找姑娘?来,先注册,从我这里填写个表(统一的格式)。<wbr>想找什么样的姑娘,看我的公告牌,上面都是待嫁的好姑娘(统一的数据)。啊,阿猫阿狗已经牵手成功了,好好好,赶紧把他们从公告牌当中删除,我们也就看不到了,脑袋里面更不会有(数据的同步),简单不?</wbr></wbr></wbr></wbr></wbr>

<wbr></wbr>

2) 控制

控制的问题其实比较简单,mediator似乎是最想解决这个问题而诞生的。

对于空间上,比如函数func1(), func2(), func3()都分别放在x,y,z文件当中,模块A调用了func1() func2(), B调用了func2(), func3(),C调用了func3(),这里他们之间的调用连线是不是很多。<wbr>如果是把函数func1(), func2(), func3()都写在一个文件当中D, A,B,C只需要知道D, 或者说只需要调用D里面的函数就行了。</wbr>

<wbr></wbr>

视频里面举那个流程改造的例子,我觉得非常的有启发性。里面的改造其实是从原始的状态机 分离成转发流程和处理流程 相互独立的过程。里面时间、空间的解耦都涉及了。

<wbr><wbr><wbr>[1] 原始的状态机涉及到至少3个参数,</wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>A 事件 B当前状态 C下一个状态 = g ( A, B)</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>g 在这里是一个单值函数,给出A,B就有唯一的C对应。一般是通过查一个二维表,</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr> 但是大多情况下是5个参数</wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr>A 事件 B当前状态<wbr>C 下一个状态</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> D 对应的处理事件 D = f( A, B )</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> E D的返回结果</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr>所以C呢,修正为C = g( A, B, E ), 或者是 g( A, B,<wbr>f( A, B) ) ,<wbr> -- 其实还是g'(A,B) 嘛,但是从编程的角度我们不考虑这些简化。反过来,我们现在要做的是把f( A, B )从 g( A, B,<wbr>f( A, B) ) 当中分离出去,C变成纯粹的C = g( A, B, E ) ,<wbr>交给全局的状态转换引擎负责。1个</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr><wbr> D变成纯粹的D = f( A, B) , 交给当前状态节点的处理函数负责。还是多个</wbr></wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr>OK,这样空间上解耦了吧。本质上就是把“当前该干什么”和“下一步是什么”给分离开来,呵呵。尽管对于人脑来说要走一步想三步,但是对电脑来说这样可不见得好。这样的好处是,对于流程节点来说,当业务发生变化的时候,比如上面视频提到的例子,对于VIP来说可以先买票 ==&gt; 再出票 ==&gt; 最后付钱,而一般会员和一次性顾客都得先付钱 ==&gt; 再买票 ==&gt; 最后出票,</wbr></wbr></wbr></wbr>

<wbr>只需要g( A, B, E ) 当中根据B, E 进行再细分,或者增加一个会员状态F,扩展成为 g( A, B, E, F<wbr>) 即可,你可能会说,此时无论如何都要修改g啊,是啊,可是这时候g已经从之前分散在各个节点当中的,被抽取出来放到那一个引擎当中去了,这时候只需要改一处即可!</wbr></wbr>

<wbr><wbr><wbr> 感受到mediator的威力了吧? 婚介所给力不,有木有?<wbr></wbr></wbr></wbr></wbr>

<wbr></wbr>

<wbr><wbr><wbr>[2] 时间上的分离,就更好理解了,即这个调用是异步的,还是同步的。如果是异步的,那么你调用了我,我什么是时候得到结果果再告诉你,你不必死等,是不是时间上分离了?</wbr></wbr></wbr>

<wbr><wbr><wbr> 这个过程发生在哪呢,发生在状态转换引擎得到E的时候,如果是引擎同步等待每个状态节点返回结果,那就没有时间上的分类了。但是视频里面使用了notify-dispatch的模式,就是引擎一个线程T1,维护一个消息队列Q。节点状态处理函数另一个线程T2。 T2就是把处理好的结果放入到Q当中,T1不停的轮询Q,有东西的时候算出来它的下一个状态是什么,然后就分发到下一个状态的节点。这时候因为异步的关系,T1得到E的时候已经丧失上下文了,所以T2最好是返回(A,B,E) 这样一个3元组P。然后T1根据P直接带入到g() 当中得到E。</wbr></wbr></wbr>

<wbr><wbr><wbr><wbr> 时间上的分离的好处我也就不必多说了。</wbr></wbr></wbr></wbr>


还是拿婚介所比喻,

空间上的分离:本来啊,你得漫无目的的在街上寻找姑娘,看到一个性感的背影,好了,空间上接近,迫不及待的想看她正面,然后心开始扑通扑通乱跳。有一句是什么来着,”望背影急刹千军万马“, 你那个兴奋啊,期待啊,可是。。。她一转身,”猛回头喝退各路诸侯“,原来是个如花啊!!!”我的妈呀“。 要是有婚介所就好了,这时候婚介所先帮你过滤了一批,你根本不需要接近这些姑娘鉴别美女。只需要看看婚介所给你的照片。。。(虽然国内PS流行)

时间上的分离:你还不甘心,继续找啊找,好不容易发现了美女,总不能让她这样就走了把,于是你鼓起勇气,厚着脸皮, 要了她的联系方式,心中无比暗爽。 而婚介所事先就帮你要到了一堆美女的联系方式,你只要去找中介即可。这时候对你来说,"找"和"要联系方式" 不是同时进行的。

<wbr></wbr>

3)地址

视频的举例i 和iii 我认为都可归类到这里,为什么呢

i举例是IoC, 解决对象依赖关系,这种依赖关系就是地址,

如A要import com.b.c.d 下的东西,要知道这个com.b.c.d在哪,如何解析这个,是不是地址的问题?

iii举例是SOA当中的Bus,解决对象之间通信的问题,既A要发给B,C,D这些对象,B要发给C, D, E, 但是呢,A, B又不想维护冗余的C,D的地址,这时候怎么办?是不是地址管理和路由的问题?其实学过网络,就知道路由器就是解耦这一过程而发明的。

<wbr><wbr><wbr> 如果说两者一些区别在于后者还一个路由的问题,这个也好办,路由的过程,是不是路由器查找路由表然后把包按照某个地址发出去?好了,路由表也是一个数据型mediator(当然实际当中,每个路由器维护的路由表是不一样的,但是这里只考虑由一个路由器连接而组成的局域网),ok,现在这个路由表原来需要A,B,C,D 各种维护一份,现在好了,由这个数据由路由器来维护了一张公共的表,呵呵。</wbr></wbr></wbr>

相当于你去相亲,不需要事先知道每个姑娘住哪,她们也不需要知道你的,到了婚介所都会一一提供。

<wbr><wbr><wbr> 连这个找路的路由算法都集中在路由器当中了,不需要每个节点都维护一份了。</wbr></wbr></wbr>

相当婚介所服务很到位,怎么去到姑娘家事先用google map 查了一份存好,你也不用自己在费脑筋、费时间去查了。每位姑娘来你家也是如此, 什么,来我家。。。。。

<wbr></wbr>

结题

<wbr></wbr>

<wbr><wbr><wbr><wbr> 所以一旦遇到”连线“数量增多的问题,使用mediator是一个好办法,</wbr></wbr></wbr></wbr>

<wbr><wbr><wbr><wbr> 如何分解这个问题,按照数据/控制/地址的方法分类,想想婚介所的例子,相信都能解决的。</wbr></wbr></wbr></wbr>

但是mediator也有个明显的缺陷,就是作为mediator的中心节点 单点失效的问题,这个就不在本篇讨论之列了

一点愚见,敬请指教!转载请注明作者和出处,谢谢!

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics