
出版社: 清华大学
原售价: 59.00
折扣价: 41.90
折扣购买: Live软件开发面面谈
ISBN: 9787302501565
第3章MVC 假如问一群程序员,谁是*有价值厨师?他们大概会在短暂的茫然后给出五花八门的答案,男朋友、老婆、老妈或者某家快餐连锁店的幕后大厨。显然他们对这个概念还不太熟悉,但是如果把它翻译成英文Most Valua**e Cook,有些人或许就明白了。假如还不知道,说出它的简称,他们就一定很熟悉——MVC。 MVC可谓是图形用户界面软件设计的标准模式。无论采用哪种编程语言,设计的是桌面端、Web还是移动端应用程序,采用的是流行的或冷门的开发框架,遵行MVC都几乎是必然的。然而另一方面,就像一千个人眼中有一千个哈姆雷特,当人们谈论MVC时,也像谈论爱情一样,所指千变万化。 视图没有直接从模型获得*新,而是由控制器修改视图,这违背了MVC的设计原则。控制器应该对视图的细节一无所知。事件响应程序可以直接写在视图内。控制器负责系统的业务逻辑。诸如此类都是关于MVC的断言。但在其他地方,又可以看到截然相反的论断。这些被我当成反面教材列出来的话语可不是初学者的臆想,它们都是来自Goo**e相关关键字搜索的结果前列,有的是Oracle官方网站上对MVC的介绍文章,有的是俄亥俄州立大学计算机科学与工程系的主题讲义,有的是编程社区网站的热门和高票文章。代码样例是程序员学习的重要来源。不幸的是,同样来自Goo**e搜索结果排名前列的MVC的样例代码却良莠不齐。很难相信这些代码的作者会以他们对MVC那样的理解和代码风格在实际项目开发中应用MVC模式。 【注: 上述部分论断和代码样例的出处www.oracle.com/technetwork/articles/j**ase/index142**0.html http://web.cse.ohiostate.edu/~rountev/421/lectures/lecture23.pdf http://www.austintek.com/mvc/ http://www.codeproject.com/Articles/613682/YourfirstprogramusingMVCpatternwithCsharpW http://www.codeproject.com/Articles/383153/TheModelViewControllerMVCPatternwithCsharp】 平心而论,会有这样的现象,部分原因是MVC不像Sin**eton之类的设计模式那样具体,没有**的代码对应形式,而且在广泛的应用中,根据环境要求和不同编程语言的特点也产生了不少变体,如MVP(ModelViewPresenter),从而令得不同情况下三个组件所负责的功能和实现方式有所出入。这样的弹性和变化进一步让MVC在传播过程中,像故事的流传一样衍变出形形色色的版本,又像娱乐节目上经常出现的接力猜谜,每一个人从上一个人的动作中猜出在模拟什么东西,再以自己的方式表演给下一个人看,到*后一个人猜出的结果往往和*初风马牛不相及。要应对这样的困境,*好的方法是不仅知其然,还要知其所以然。本章将从简单程序的结构入手,逐步分析一个自然合理的架构随着程序的演变,如何发展成MVC。从分析MVC架构体现的设计理念辨清它的真相,理解在它的种种变体中哪些不变的部分是逻辑要求的必然结果,又有哪些部分可以适应需求、环境和实现技术做出灵活的选择。这之后再讨论桌面、移动和Web环境下MVC的具体实现。 3.1输入、处理和输出 输入、处理和输出是早在计算机出现之前就可以从人类发明的很多机器抽象出来的模式。对蒸汽机来说,输入的是煤,处理是燃烧产生蒸汽,输出的是机械动力; 电灯输入的是电流,处理是灯丝通电升高到足够的温度,输出的是光。而*典型的可能莫过于一台全能猪利用机,输入的是活猪,处理是在一个闪闪发光的密封金属舱中轰隆隆地进行,输出的是香肠、皮鞋、毛刷和骨头汤。所以从计算机的架构中也能看出这种模式,是毫不奇怪的。这种抽象的模式不仅适用于硬件,对我们关心的程序开发而言也是一种很自然的结构。本节将探讨它在命令行程序中的表现形式。 3.1.1冯·诺依曼架构 1936年英国数学家图灵(Alan Turing)提出了一种想象中的机器——图灵机。这种机器的构造十分简单,只包括一条无限长的带子、一个读写头和一个状态存储器,然后机器根据读写头读取到的符号和当前状态以及有限条规则*作。图灵表明任何一项具体的计算,都可以由一台特定的图灵机完成。再进一步,将描述如何进行一项具体计算的规则也记录在带子上,由一台特殊的图灵机读取,那么它就可以完成那台特定的图灵机的计算。这样一台可以模拟所有图灵机,也就是可以进行任何计算的特殊的图灵机就被称为通用图灵机,它是现在所有计算机理念上的先驱。 1945年,出生于匈牙利的数学家、物理学家和科学全才约翰·冯·诺依曼(John von Neumann)在美国的宾夕法尼亚大学参与埃尼阿克研制工作时向美国*方提交了First Draft of a Report on the EDVAC(电子离散变量自动计算机报告初稿,EDVAC即Electronic Discrete Varia**e Automatic Computer)。这份报告虽然只有个不起眼的名称“初稿”,却和其他奠基性的文献一样,完整地建立了一台电子计算机的架构。冯·诺依曼首先描述了作为主题对象的“计算机”,它是一台能高速计算的电子设备,胜任求解物理和工程中常见的多变量偏微分方程,把要解决的问题的参数和描述求解方法及步骤的命令以某种方式输入后,它就能在没有任何人工辅助的条件下将结果计算出来并以某种方式输出。接着冯·诺依曼将计算机从逻辑上分成五个部分,分别完成特定的功能。这台机器被设计的主要用途是进行数学计算,所以自然有一个部分专职于此,即中央算术组件(Central Arithmetical Part,简称为运算器),它负责进行加减乘除等基本运算。第二部分叫作中央控制组件(Central Control Part,简称为控制器),负责执行指令,指挥运算器所做计算的次序,协调计算机的所有组件统一工作。第三部分称为存储器(Memory),用于保存计算过程中用到的各种信息,包括要解决的问题和计算产生的中间数据等。冯·诺依曼列举了计算机可能解决的各种数学问题,分别估计它们需要多大的存储空间。第四部分是输入设备,计算机的*作员通过它将待解决的问题和计算机执行的命令输入计算机,冯·诺依曼提到了当时可用于此的几种技术: 在打孔卡或电传打字机纸带上打孔,在钢带或钢线上用磁记录,在电影胶卷上用摄影技术记录,通过插接板的连线配置……不过在这个人类发明的长长清单里键盘还没有出现。第五部分与第四部分相对,是输出设备,用于将计算结果传导到某种人可以直接或间接读取的载体上,也是利用上面列举的技术。 这份报告不仅指导建成了一台电子计算机,而且其中的很多讨论和分析对以后世世代代的计算机都有效,原因就是它一方面体现了*一般的自动计算机模型——图灵机的思想,另一方面又将通用图灵机的模型用*贴近实际制造和*作的方式设计出来,并且以当时的电子技术为基础,对计算机的各个部分做了具体的分析。报告将计算机从逻辑上分解成运算器、控制器、存储器、输入和输出设备五大部分,也被后人称为冯·诺依曼架构。计算机已经经历了从“埃尼阿克”的庞然大物到如今人手一部的智能手机的沧桑巨变,然而五大部分的分类仍然有效。 将冯·诺依曼架构和通用图灵机模型作比较,计算器、控制器和存储器三者的组合已经实现了通用图灵机的功能,输入和输出设备则是人类与机器交互的手段。我们再从机器转向程序的视角,每个具体的软件都具备一个或一组特定的功能,计算机读取和执行该软件的代码,就变成了一台特定用途的图灵机。软件的用户以某种渠道输入数据,软件进行处理,完成后再以用户能理解的方式输出。这样类比于冯·诺依曼架构,一个软件就可以被划分为输入、处理和输出三部分。这个划分看上去平凡无奇,但接下来的讨论将让我们看到它是怎样逐渐演变成MVC模式的。另外为了和MVC对应,我们给输入处理输出结构也起了一个很酷的简称IPO(即英文I**utter、Processor和Outputter的简称)。 3.1.2矩阵运算器和IPO 先来看看图形用户界面产生之前的命令行应用程序。假设现在要开发一个简单的矩阵运算器,可以求矩阵的转置。我们的思路很自然地就集中在怎样设计出一个能代表矩阵的数据结构,并在它上面实现转置的算法。对于这个简单的问题,既可以采用过程式编程,也可以应用面向对象编程。为了与以后讨论的问题保持一致,这里以面向对象的范式来思考。这样得到的结果是一个矩阵类型Matrix,包含一个求转置的方法Transpose(这里径直采用面向对象编程中基于类型的途径,但选择基于原型等其他途径并不影响我们的分析)。这时候我们就会发现,矩阵运算器的核心虽已完成,但要成为一个可使用的软件,还需要增添其他一些部分。从矩阵类型的视角来看,在进行转置运算前,要先为矩阵的元素提供数据,也就是初始化一个矩阵对象。从软件用户的视角来看,他要解决的是求一个个矩阵个体的转置,因此先要将这些个体告诉矩阵运算器。在命令行应用程序的环境下,告诉的方式便是在控制台(Console)上将矩阵的元素以某种格式用键盘输入。可以设想很多种格式,例如先输入两个数字,表明矩阵的阶数,然后输入空格分隔的所有矩阵元素; 或者直接输入矩阵元素,每行元素输入完成后换行; 还可以用括号将每行元素包括起来,这样就不用换行。等到运算器完成计算后,用户也要能在屏幕上看到结果。转置后的矩阵既可以以与输入相同的格式输出,也可以按照矩阵的行列分布以直观的形式打印出来。这些需求对应到矩阵运算器上,就意味着两项新的功能: 一是读取用户在控制台上以某种格式输入的字符,利用其要传递的信息,初始化一个矩阵对象; 二是将转置后的矩阵以用户能理解的形式打印到控制台上。至此,我们对软件抽象划分出的三部分在矩阵运算器上就有了对应物。处理的部分对应矩阵类型,输入和输出的部分分别对应上述两项新功能。为了简便,我们不妨把三者分别称为输入部分、处理部分和输出部分。我们为输入部分和输出部分也分别创建一个类型: I**utter和Outputter。这样程序的运行顺序就大致如下。 《Live软件开发面面谈》为一线软件开发人员对实践中常见易混乱的概念和难解问题的总结和解惑,例如针对接口编程就是尽量多用接口吗?事件驱动编程的本质是什么?怎样算是应用了MVC架构?极简主义就是越简单越好吗?文档型数据库和关系型数据库的优劣各在什么地方?在主流的软件开发理念之外能否另辟蹊径?客户端和浏览器之间的竞争究竟意味着什么?有助于读者深入思考、追本溯源、融会贯通,既对实际开发有帮助,又有益于在纷繁多变的技术浪潮中看清本质、把握方向,并从软件开发行业快速跳动的脉搏中读出一些共性和规律。