首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >经典软件架构模式(二)

经典软件架构模式(二)

作者头像
韩伟
发布2018-03-05 15:21:58
8380
发布2018-03-05 15:21:58
举报
文章被收录于专栏:韩伟的专栏韩伟的专栏

今天继续推送“经典软件架构模式(二)之管道和过滤器模式、MVC模式。

管道和过滤器模式

第三个案例是一个WEB的例子,但并不是简单的CGI加数据库,而是一个在网站上点播图文铃声短信、订阅各种短信服务的系统。从界面上就可以看到,这个网站可以下发不同的歌曲铃声,各种手机格式的图片,还有一些特别的文字短信,这些称之为“点播”服务。

网站上搜集了大量的铃声、图片、文字来提供此功能。另外一类称之为“订阅”服务,就是每天会不定时发一些最新的新闻、黄历、心理测试等短信内容给订阅了服务的手机号。最后一类比较复杂,属于交互性服务,比如彩票、交友、股市、邮箱,这些服务让用户可以通过发送短信来和系统互动,比如查某个股票的价格,购买彩票,发布自己的交友信息,查收邮件内容等。总体上此网站的功能比较复杂,但大部分是把信息从互联网发送到手机上。

【此案例并非完全真实情况,有一定提炼修改成分】

为了建设一个这样的网站,一般来说最开始,都是从两个模块开始:一个WEB网站,一个收发短信的进程。WEB网站最常见的方案,就是用PHP或者其他类CGI的程序,连接一个数据库,然后把页面展现给用户。

因此我们按照业务模块,把这些PHP划分成图片、铃声、文字短信、新闻、黄历、邮件……等等的模块,每个模块负责展现业务内容。当这些模块需要发送短信的时候,就把要发的短信的内容写到数据库的某个表里面。然后短信收发进程就从数据库里读取内容,发往各个不同的运营商的短信网关。

这样的系统本身是问题不大的,但是随着用户量的增长,首先出现了一个要命的情况:数据库负载很高。因为用户访问WEB网站需要读写数据库,发送短信也要先写数据库,短信收发进程也要先读后删数据库记录,这让数据库不堪重负。或者说,本身让数据库来承担这种“消息队列”通讯就是错误的用法。

同时,也发生了另外一个问题:由于接入的手机运营商越来越多,当时都是分省接入的,短信收发进程变的非常复杂,其原因是发送短信的内容并非只有收、发手机号和发送文本这3个字段而已,而是还有很多其他的逻辑要处理。譬如说每条短信都要填一个“业务代码”,代表了短信的资费信息,然而每个省运营商申请的代码都是不同的,一条新闻发往不同的短信网关,需要填写不同的“业务代码”。有时候还会需要“套用”和“借用”一些业务代码。这样的复杂逻辑代码都塞到每个短信发送进程里,随着频繁的商务关系的变化,全部修改起来非常麻烦。

因此我们做了一次重构,核心思想是把发送短信的各个流程,划分到不同的模块里,形成一个工作流。然后使用文件代替数据库,作为消息队列;加入专门处理短信商务关系的业务模块,统一解决类似“业务代码”的问题。这样处理之后,所有的处理过程都被分割在单一的模块里,可以很方便的单独修改。

这种架构,实际上就是“管道和过滤器”架构:把一个需要多重步骤处理的数据流程,分割为多个独立的处理模块,称之为“过滤器”,然后根据业务需要,把“过滤器”连接成处理数据的“管道”。所有的代码,都要符合“过滤器”的要求,也就是要针对特定接口“数据”的输入端和输出端。而且这些输入和输出端是可以互相连接的。

“管道和过滤器”——非常适合分布式系统

● 适应:面向数据处理。在很多情况下,我们都是需要处理某种特定格式的输入数据,然后结果输出成某种数据。这种“单进单出”的模型是非常常见的情况,比如在编译器、Shell脚本系统、网络处理系统。特别是如果你需要让多个服务器共同工作,最简单的方式就是写很多个进程充当“过滤器”,然后监听TCP/IP端口,等待需要处理的网络包,结果则是通过发送网络包给另外一个后续步骤处理的进程。由于过滤器进程天然的可以使用操作系统的网络功能,因此很容易让多个不同服务器上的进程系统工作起来。

● 不适应:输入输出复杂系统。假如是做一个人机交互的GUI程序,或者是一个输入有多个输出的程序,这些都打破了“单进单出”的模型,就不太适合这种模式了。当然你也可以强行这么做,结果就是要写很多代码把大量的输入和输出数据整理成单个输入、输出的的数据模型。

● 方法论:关注数据处理步骤。构造这种模式的方法,最重要的是切法数据的处理步骤,一般来说我们会根据处理的计算消耗,以及处理步骤所需的数据模型复杂程度来切分。在分布式系统中,我们会希望不要让一个过滤器的负担过重,影响服务器负载的均衡;在其他的系统中,我们希望每个过滤器的编程接口尽量简单,而不是要面临大堆复杂的状态值。

● 设计模式实现:

● 装饰器模式——我们可以通过组装多个过滤器对象,构造出一条处理管道。java.io库就是一个最典型的例子。

● 责任链模式 ——责任链就是一个典型的处理管道,我们可以用这种模式几乎一一对应的实现出管道和过滤器模式。

MVC模式

当我们要写一个GUI程序的时候,基本上都想到这种著名的架构模式。因此我们举一个简单的例子:MP3播放器。这个系统有播放按钮、进度条、播放状态、播放列表、歌词等部分,这些部分都要结合到一起来适应正在播放的一首歌。

【此案例并非完全真实情况,有一定提炼修改成分】

如果我们只是简单的思考如何实现,往往会做的比较简单:我们按照可以显示的部分,划分出几个模块,譬如播放按钮模块,进度条模块,播放状态(歌曲标题)面板,歌词面板等等。然后在所有可以操作的GUI控件上增加操作事件函数。比如按下播放按钮,各个面板和进度条就开始显示对应的信息。但是,如果面板和按钮变多了,我们会发现写在事件函数中的代码会越来越复杂,因为整个界面的各个部分,都是关联的。按下一个按钮,可能需要修改多个面板,一旦写漏了一个逻辑,那个面板的显示就是错误的。随着UI界面变得复杂,这种关系会呈几何式增长,最终代码会变得不可维护。

但是实际上,我们只要稍加思考就会发现,只要加入一个表示“歌曲列表”的不可见的状态对象,就能大大简化这种关系。

由于操作UI基本上都是去修改播放的状态的,所以他们只需要管理这个对象即可。而所有的显示UI,都是从这个播放状态对象读取数据,不管具体要如何操作。而这个结构里的“播放状态对象”,就是MVC模型里面的Model,操作UI中的事件函数,就属于Controllor,而显示UI的模块,就是View了。

MVC模型本身并非是只有一种标准方案,而是存在多种不同的描述的。但是他们基本上都会把系统的模块定义为M\V\C三类。对于这三类模块之间的耦合,定义了一些必须遵守的原则。一般来说,会把程序的状态放在M型模块里,而供用户操作的代码,放在Controllor类型的模块,View类型的模块就专心的负责根据Model的数据来做效果显示。注意MVC模型并非“三层结构”!因为彼此之间形成对客户程序的屏蔽,而是互相之间都有双向的管理。

“GUI首选”——交互界面频繁改

● 适应:多变的交互界面。此模式1978年由Xerox PARC发明,用来配合Xerox发明的GUI界面的开发。是一种非常专用的架构。

● 不适应:非交互领域。需要注意的是PC程序中除了GUI部分,譬如游戏里面的场景——往往不是界面UI的,坚持使用MVC往往容易造成不必要的复杂。

● 方法论:以交互特征划分模块。区分出系统中哪些是需要“人”来操作的,哪些是用来单纯“输出信息”的,哪些是内部的状态,就是构造MVC系统的关键。

● 设计模式实现:

● 观察者模式——一般来说在View对Controllor的触发上,为了避免直接的耦合关系,都会使用观察者模式。有些做法下,Model会和对应View的“同步绑定”,他们的刷新事件,也是通过观察者模式的Update事件来通知。

感谢大家的阅读,如觉得此文对你有那么一丁点的作用,麻烦动动手指转发或分享至朋友圈。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2015-12-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 韩大 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 管道和过滤器模式
相关产品与服务
短信
腾讯云短信(Short Message Service,SMS)可为广大企业级用户提供稳定可靠,安全合规的短信触达服务。用户可快速接入,调用 API / SDK 或者通过控制台即可发送,支持发送验证码、通知类短信和营销短信。国内验证短信秒级触达,99%到达率;国际/港澳台短信覆盖全球200+国家/地区,全球多服务站点,稳定可靠。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档