经典软件架构模式(二)

今天继续推送“经典软件架构模式(二)之管道和过滤器模式、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事件来通知。

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

原文发布于微信公众号 - 韩大(handa1740168)

原文发表时间:2015-12-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏我和未来有约会

Silverlight第三方控件专题

这里我收集整理了目前网上silverlight第三方控件的专题,若果有所遗漏请告知我一下。 名称 简介 截图 telerik 商 RadC...

4395
来自专栏pangguoming

Spring Boot集成JasperReports生成PDF文档

由于工作需要,要实现后端根据模板动态填充数据生成PDF文档,通过技术选型,使用Ireport5.6来设计模板,结合JasperReports5.6工具库来调用渲...

1.4K7
来自专栏大内老A

The .NET of Tomorrow

Ed Charbeneau(http://developer.telerik.com/featured/the-net-of-tomorrow/) Exciti...

38610
来自专栏陈仁松博客

ASP.NET Core 'Microsoft.Win32.Registry' 错误修复

今天在发布Asp.net Core应用到Azure的时候出现错误InvalidOperationException: Cannot find compilati...

5228
来自专栏Ceph对象存储方案

Luminous版本PG 分布调优

Luminous版本开始新增的balancer模块在PG分布优化方面效果非常明显,操作也非常简便,强烈推荐各位在集群上线之前进行这一操作,能够极大的提升整个集群...

3675
来自专栏一个爱瞎折腾的程序猿

sqlserver使用存储过程跟踪SQL

USE [master] GO /****** Object: StoredProcedure [dbo].[sp_perfworkload_trace_s...

2870
来自专栏跟着阿笨一起玩NET

c#实现打印功能

3712
来自专栏张善友的专栏

Miguel de Icaza 细说 Mix 07大会上的Silverlight和DLR

Mono之父Miguel de Icaza 详细报道微软Mix 07大会上的Silverlight和DLR ,上面还谈到了Mono and Silverligh...

2997
来自专栏C#

DotNet加密方式解析--非对称加密

    新年新气象,也希望新年可以挣大钱。不管今年年底会不会跟去年一样,满怀抱负却又壮志未酬。(不过没事,我已为各位卜上一卦,卦象显示各位都能挣钱...)...

5968
来自专栏张善友的专栏

Silverlight + Model-View-ViewModel (MVVM)

     早在2005年,John Gossman写了一篇关于Model-View-ViewModel模式的博文,这种模式被他所在的微软的项目组用来创建Expr...

3278

扫码关注云+社区