2011-03-09 22:17 MVC模式与项目开发

原文地址:http://hi.baidu.com/wuwei0814/item/6f457ccbf3d257d7ee183be9

 

在学习任何一门面向对象的编程技术并熟悉它的基本语法和编程API后,都会进入使用具体语言进行软件项目开发的领域。面对一个应用项目我们该从何处入手?怎样的代码设计可以为将来打下最坚实的基础呢?所有这些问题我们将在本章给出一些基本答案:那就是我们在前文里已经介绍过的—设计模式思想。

设计模式作为前人在软件开发领域中优秀设计的经验总结,对我们加深面向对象分析与设计的理解是大有裨益的。通过复用已经公认的设计,我们能够在解决问题时争取获得先发优势,而且避免重蹈前人的失败覆辙。设计模式让我们可以从学习他人的经验中获益,用不着为那些总是会重复出现的问题再次设计解决方案。

13.1 MVC模式概述    

学习设计模式根本原因是为了代码复用,增加代码可维护性。

那么,怎么才能实现代码复用呢?OO界(面向对象)的前辈的对此总结了几点原则:“开-闭”原则(Open Closed Principal)和合成复用原则等待。用作软件架构布局的MVC模式同样也循序了这些原则,MVC模式为我们提供对观察问题、设计过程和面向对象的更高层次的视角,将我们从纷繁复杂的局部细节中解放出来。

关于MVC模式的具体使用方法我们将会在稍后的小节里具体介绍,之前我们先来了解一下软件设计原则中最重要的“OCP原则”的相关知识。

13.1.1 OCP 原则与模块分离思想   

一看这个标题,可能在你的脑袋里冒出一个个问号,什么是OCP原则,什么又是模块分离思想。我们要学习什么枯燥高深的软件工程理论嘛。比起一行行看得着摸得到的程序代码来,这些软件开发的理论确显得太过晦涩和抽象了,特别是对于没有做过软件项目的学习者来说更是这样。

但讲到这里,我们要说,这个两个是相互联系的概念:OCP原则与模块分离思想对于软件开发和程序设计来说是十分重要的,是每个软件开发者必须深深明理的指导,其实我们在软件开发的过程中,都已经有意无意地用到了OCP原则和“分离”的思想。到这里,我们想你此刻肯定又多打起一份精神,来学习这个这个两个知识点了吧,因为你已知道它们对软件开发和程序设计来说是多么重要。

    什么是OCP原则?它的字面意思是“Open-Closed Principle”,我们称它是“开-闭原则”,它是众多设计模式的基础。接着让我们理解有关于“开-闭原则”背后的真正内含:OCP原则认为:一个软件应该对扩展(比如通过修改代码来扩展功能)开放,对功能修改关闭。也就是说,软件应该设计得在不对它修改的前提下就可以完成其对功能的扩展,扩展可以具体表为对模块、对类、对方法的扩展开放。

先暂停一下,我们先说一个题外话:任何软件设计的指导性原则,都是来自于人们长期软件开发真实工作经验的总结和提炼。换一个顺序角度思考,当人们长期从事软件开放工作后,发现了许多成功的、优秀的软件项目,在它们的身上有些共性特征,于是人们就把这些共同的优秀的特征提炼了出来,就成为我们现在看到这些原则。真是应验了这么一句经典名言:理论来源于实践,反过来理论又可以来指导实践。

罗唆地讲了这么多是为了指出“OCP原则”是有生命力,当使用面向对象编程语言进行软件开发时,为了达到所开发的软件模块或组件具有可重复使用的特征,那么这些软件在设计和开发阶段必须遵循“OCP原则”。一个符合“OCP原则”的软件模块或组件,它们一定是具有可重复使用特征的。

    我在第一次听到这个OCP原则说的:软件应该对扩展开放,对修改关闭思想时,恩?这听起来实在是有些矛盾。难道在不修改已有的代码的前提下,就可以对现有模块进行功能的扩展?但事实上一些优秀设计模式和软件产品已经很好的证明了这点,如果我们开发Java语言时,使用的是Eclipse开发平台,可以发现,为Eclipse增加新的功能就像增加插件这么简单,这就是成功应用OCP原则一个典型案例。

我们可以慢慢得出这样一个观点,OCP原则的实现,对外的直观表现就是功能模块分离,事实上确实是这样,说到OCP原则就不得不讨论接着的话题-模块分离思想。模块分离思想指的是软件模块化设计和开发,可以说OCP原则和模块化设计互为因果关系。

    对软件体系结构按功能进行划分,保持模块“功能独立”是模块化设计的基本原则。因为,“功能独立”的模块可以降低开发、测试、维护等阶段的代价。但是“功能独立”并不意味着模块之间保持绝对的孤立。一个系统要完成某项任务,需要各个模块相互配合才能实现,此时模块之间就要进行信息交流。各个模块的具体内部设计技术,如实现变化的各种封装、实现按接口编程等等技术已经大大超出了《Java第一步》的范围了,就不在继续展开了。 

软开发完全遵守OCP原则是十分困难的,但是我们可以把它作为我们进行软件设计和开发的目标,引导的正确方向。软件设计和开发越是遵循这一原则,将来它满足新需求的功能扩展就来得越轻松。

下文里的MVC模式,它就是遵循OCP原则的一个典范,它由于引入了“模块分离”等的原则,所以MVC 模式可以很好地反应出OCP原则的一些优势。

13.1.2什么是MVC模式    

MVC模式即模型-视图-控制器(model-view-controller)模型,它最早在smalltalk-80的应用程序中出现,目前对该模型的准确定义还存在着一些争议,大多数人将其归于设计模式,也有人将其定义成一种架构模式。

从本质上讲,MVC模式是对于GOF23种设计模式中一些基本模式的集合和优化。MVC模式是目前交互式系统中应用最广的一种分层架构,它可以很好地隔离用户界面层和业务处理层,对代码进行模块化的划分,将一个系统中的各个功能部分之间进行“解耦”,它的示意图如下:

图13-1 MVC模型示意图

让我们边阅读下面的分析,边来理解这幅图MVC原理图的含义前,不得不说的题外话。MVC设计模式正如其名它在设计和开发时是按照“M-V-C”即“模型-视图-控制器”的顺序展开的,这背后是有原因,姑且就先知道这层“顺序”要求吧,算是我们步入MVC的第一步。接着我们在分析MVC原理时也将按照这个顺序进行。

13.1.2.1模型层

模型层表示业务数据和业务逻辑,它的任务是执行对数据的操作,如对数据增,删,改,查。模型是专门负责维护数据的,它本身并不能决定这些数据对用户端的表示方法,而只是提供一些对外的接口,这些接口包括取值或者改值方法,让视图和控制器可以获得模型的内部参数或者对其进行修改,(如图中查询数据和修改数据)。当我们看着这幅图,其中有两个箭头指向了模型,用面向对象的观点进行思维,可以得到如下的结论:

1.         模型层必须负有这样的责任,而这些责任在Java程序中就对应着一个个的方法(或者是一个个业务逻辑),这些责任有什么功能呢?正如箭线上简略说明一样,查询数据、插入数据、修改数据和删除数据。

2.         第二层意思,这些责任又被谁用到呢?很显然它首先会被视图用到,其次会被控制器用到,这些所谓的用到在Java程序中就相应着在视图层的类中肯定有这么些代码,它们调用了模型的这些责任。不要小看了这些看似很教条化的表述,这其中就包含着面向对象设计的些最核心的思想:强内聚,低偶合(模块内强内聚,模块间低偶合)。

好了,我们继续看图说话。

另外,模型必须提供登记视图的方法!嗯?之前不是说指向模型的箭头就表示模型应具有的责任即一些方法嘛,可是在图中我们并没有看到有什么明显的指向模型箭头,表示模型必须提供登记视图的方法,这往往是很多初学MVC设计模式人们最困惑的地方。没关系,让我们为你指出这其中的玄机,你看从模型出发有一个箭线指向了视图,对此我们毫无疑问,它对应着视图负有这样的责任,模型要调用视图的方法。于是乎,势必在模型对象内它必须要得到视图对象的引用,记得我们说过MVC代码在设计时的先后顺序吗。

现在,问题出来了,在构建模型对象时视图对象还没有创建,也就是只能在模型对象创建之后才能让模型对象得到视图对象,那么在模型类中必须设计一个方法,它负有这样的责任,它对外可以将视图对象注册进来,即模型对象可以得到视图对象,那么模型对象才可以调用视图对象的方法。从视图角度理解,视图通过调用这个模型的方法将自己注册给相应的模型对象,那么之后模型对象才可以通知自己(视图对象)。加深些理解,能不能不同的视图对象调用同一个模型对象的登记视图方法呢,将几个不同视图对象注册进一个模型对象,即同一个模型对象可以为不同的视图对象服务呢?答案是肯定的,从项目需求角度来分析,也必须要求一个模型对象可以为不同的视图对象服务。一个模型能够为多个视图提供数据,可以被多个视图重用,这样提高的代码的可重用性。

在上文里,我们讲了一些比较抽象的概念,下面我们来举一些模型层的例子:我们在Java Web开发架构里的JavaBean,或者是EJB,都可以承担模型层的角色,讲得再简单一些,哪怕我们用纯粹Java来开发项目,就像下文里“贪吃蛇”的例子一样,一些涉及到业务逻辑的方法,都可以归结成模型层。

13.1.2.2视图层

在详细分析了模型的设计和运行机理后,在来看视图就显得容易多了。

视图是直接与用户交互的界面, 视图的任务是表达数据和接收用户动作,并把动作的请求传递给控制器。视图可以调用模型提供的取值方法查询业务状态,但是不能直接改变模型的数据,视图接受用户动作要求改变显示数据,必须经过控制器,有控制器负责调用对应的模型中相应方法修改模型中数据。当然在模型完成修改自身数据后,视图还能接受模型发出的数据改变的通知事件,同步更新用户界面。

MVC中一个模型可以被多个视图调用。当需要的时候,只需动态地将视图登记给模型即可。

细心的读者,可能会提出这样的问题,为什么视图不直接调用改变模型数据的方法呢,转而通过调用控制器的方法,由控制器负责转发用户的各种请求,包括将其中的请求转发给模型。这就是设计模式,前人的经验结晶,虽然不肯否认,这样做会增加代码的复杂度,但这样做将得到优势确大大多于由于代码复杂而带来的繁琐。由于请求转发的功能被独立成控制器层,带来自身和它其他模块的代码复用性增强,代码可维护性增强。视图模块只负责接受用户请求,选择适当方式显示数据,至于请求怎样分发,分发给谁,数据怎样保存,怎样修改,这些都无用关心。这里我们再体会到模块分离思想在MVC模式中的具体应用。

我们前文里讲的Java Swing包,就可以用来开发视图层的代码,在后文里将会提到的JSP语言,更是开发视图层的良好利器。

13.1.2.3控制器

控制器的任务就是来执行动作,即是要处理由视图接受的各种用户动作。控制器可以说是MVC中的中枢系统,当用户通过视图,通过提交请求发出更新模型状态指令时,这种更新是通过控制器进行的。它接收到视图传来的用户动作,发现需要对数据进行修改时,调用模型提供的改值方法完成对数据的修改。控制器在把动作执行完之后,返回给用户一个结果。而如果执行成功了,视图需要调用模型来表示数据(查询数据);

可以看出,控制器的作用相当于一个分发器,它决定着哪个视图的请求转发给哪个模型,可以完成什么样的用户请求。但是控制器本身并不做任何的数据处理,它只是起了一个“甄别”与“传递”的作用。因此,模型与视图之间是一种“多对多”的关系。在MVC模式中,一旦模型数据发生改变了,那控制器将会通知所有依赖于它的视图进行更新。

当我们用Java开发Web应用时,会遇到一个名叫“Servlet”的模块,它简直可以说是控制器的代名词,在后面的篇幅里,我们可以看到Servlet如何完成“分发请求”的动作。

13.1.2.4 MVC模型编程综述

在上文里,我们已经分别讲述了MVC各层的作用,在这部分里,我们将提前讲述一下基于MVC模型模式的两个注意点:

第一点,既然MVC模式已经按业务逻辑的种类做了“分离”,那么我们在实现MVC模式的过程中,不能再进行“混合编程”,即不能在视图层里编写业务逻辑。

这个似乎是废话,但是这样的情况稍微不注意就会发生。比如,JSP代码可以理解成是ASP和JAVA的混合体,所以经常会有程序员(尤其是初学者)在用JSP编写视图层网页时,无意地加入连接数据库的动作。这看上去似乎很方便,通过一个文件实现了两类业务,但如果我们要在视图层变更网页的显示方式,由于在网页里我们耦合和ASP元素和业务逻辑,修改起来会“牵一发而动全身”,这倒也应验了一句民谣,“要把鸡蛋放在多个篮子里”。

第二点,MVC模式是个整体,为此,我们甚至可以牺牲模型层的代码效率来保证MVC模式的可扩展性和可维护性。因为在MVC模式里讲究的是团队合作精神而不是个人英雄主义,MVC模式的设计动机是基于OCP思想提高代码的可维护性和可扩展性。

在后面章节里提到的J2EE和SSH架构里,我们都可以看到MVC模式的设计动机,那就是“分离”思想。

13.1.3 MVC模式的工作流程    

MVC的工作流程可以如下图所示。首先,控制器通过视图来接受用户的请求,并调用相应的模型;模型根据请求对数据进行相应的业务逻辑处理,并返回数据,同时控制器将信息同步反馈给视图;模型的业务逻辑处理完成后,通知视图结果的改变,并在视图上刷新模型的数据。

在我们书写代码的过程中,我们可以按照这样书写顺序来应用MVC模式:先设计模型模块,再设计视图模块,最后设计控制模块。

图13-2基于MVC模式项目的基本代码流程时序图

从上图13-2里,我们可以看到基于MVC模式项目代码的大致时序,同样,我们可以按如下的步骤,根据时序图里的流程,具体设计基于MVC模式的项目:

13.1.3.1第一步: 设计模型接口

怎样设计模型接口即怎样确定一个接口中要有的方法?

答: 根据箭头设计接口模型中的方法。

角度一: 实现模型接口的类, 它的对象要有什么功能,也就这个对象要对外提供哪些方法呢? 如要求模型提供"查询数据",那么模型模型就必需有对应的方法实现该功能, 在I模型中我们设计public String getMessage();方法;控制模块调用模型模型模块,要求模型模型"修改数据",在I模型中我们设计public void setMessage(String msg);方法; 

角度二: 这个模型模块它自身要调用其他哪些模块?  例如: 模型模块调用视图模型模块的方法, 告诉视图我的数据已经改变了,请你自己刷新下. 对这样的需求, 在模型类的设计时,必须对外提供这样的方法,它完成将特定的视图对象注册到模型对象中去.那么之后模型对象才可以通知视图视图对象, 至于视图视图对象怎么做,那是视图类自身方法的事情, 在代码中的表现就是模型类的通知方法中肯定有视图类型对象的引用变量,而这变量往往就是Interface形式, 然后”变量名.方法()”

说法二: 另外我们发现,"模型对象"也调用"视图对象",但是在初始创建"模型对象"的时候"视图对象"还不存在, 所以要求我们为模型在提供一个方法, 该方法被"视图对象"调用, 它的作用是在创建"视图对象"后, "视图对象"将自己注册给"模型对象". 或者这么理解, 因为"模型对象"要操控"视图对象"(通知视图), 所以我们怎么使一个"模型对象"得到一个"视图对象",(1)通过在构建"模型对象"时由构造器传入"视图对象" (2) 通过提供一个对外的方法实现为"模型对象"绑定一个"视图对象"成员. public void add模型Listener(I视图);“模型对象”得到“视图对象”成员

13.1.3.2 第二步: 设计视图接口, 基本方法同模型接口的设计

按照上图13-2里的箭头方向,有指向的箭头表示视图模块的对象将被其他对象调用,也就是其他对象在得到视图对象引用的前提下会调用视图的方法。这些方法是视图模块的“必须”方法,是视图接口定义时必须声明的。

从视图模块指出的箭头表示在视图模块中调用那个箭头所指对象的某个方法,当然了,在视图的实现类中肯定会用到哪个类型(Class)变量的引用,如在视图中会用到控制器类型的变量。因为视图的对象要调用控制器对象的方法。

为了使视图类的中控制器类的变量在视图对象状态下可以指向具体的控制器对象,解决方法在视图对象构建时有构造函数传入,此方法在这不可行—在视图对象构建时,控制器对象还不存在。采用为视图接口设计一个方法add视图Listener(I控制器) ,这个方法被控制器类使用表示控制器对象将自己注册给视图对象。具体体现在控制器类设计时,在控制器的构造函数中使用视图,比如add视图Listener(this)。

13.1.4为什么要使用MVC模式    

软件设计有一个原则,叫“开-闭原则”。开表示对软件扩展能力开放,对源代码修改关闭。设计模式就是为了让软件达到或者接近“开闭原则”。对软件扩展能力开放就是指软件要增加一个模块,要能很轻松地增加,而不是具有很高的复杂度。对源代码修改关闭就是在软件扩展的同时,原来模块的源代码要做到尽量不修改。

根据软件工程理论,软件开发完成后的功能扩展,业务逻辑需求等工作量在项目开发过程中的比重不亚于项目开发和测试,所以,一个项目是否具有良好的可维护性和扩展性,是衡量软件设计的完善程度的标准。MVC框架在软件中的使用,能够使软件更理想地实现“开闭原则”。

13.1.4.1 MVC的优点

MVC是目前最常见的J2EE应用所基于的体系结构.它主要适用于交互式的WEB应用,它的优点主要表现在:

1.         多个视图可以共享一个模型,这就意味着代码的重用性可以极大地增加。模型相应用户所返回的数据是一种未格式化的数据,用户选择哪一种视图,那么视图就将数据相应地格式化并呈现给用户。这些模型可以直接应用于接口的使用。这对于解决应用程序访问方式的日渐多元化是一个很好的解决方法。

2.         模型,控制器与视图三层之间是相对独立的,在很多时候,软件所需要的改变只是集中于一层,我们并不需要对其他两层的代码做任何改动,这样代码的耦合度就低,灵活度和可扩展性都得到了提升。

3.         控制层可以将不同的视图和模型进行组合,从而完成不同的请求。

4.         MVC讲应用程序划分为相对独立的三层,这很有利于软件开发队伍的管理。通过采用MVC模式的思想开发项目,我们可以让整个团队分工明确,让各位成员各司其职,这样就更加有利于软件开发的高效性,节约了管理成本。

13.1.4.2 MVC的适用性

从适用范围来分析,MVC模式可能不大适合于开发中小型的应用程序。因为MVC的内部原理相对复杂,我们在将它应用到我们的程序当中时,需要进行详尽的设计和规划,这会带来额外的复杂度和工作量。

但是,如果我们面对的是业务逻辑比较复杂的大型应用程序,那么MVC框架是很好的选择,它会大大提高后期开发的效率,并且使软件的可扩展性,代码重用度和结构性方面都上升到一个更高的高度,这将降低项目后期维护和扩展的风险和成本。

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值