1.MVC概述 1.1 什么是MVC MVC是MODEL_VIEW_CONTROL的缩写。MODEL_VIEW_CONTROL是软件设计的典型结构。在这种设计结构下,一个应用被分为三个部分:model,view和controller,每个部分负责不同的功能。model是指应用程序的数据,以及对这些数据的操作;view是指用户界面;controller负责用户界面和程序数据之间的同步,也就是完成两个方向的动作:一、在根据用户界面(view)的操作完成对程序数据(model)的更新,二、将程序数据(model)的改变及时反应到用户界面(view)上。 1.2 MVC的优点 使程序结构更加清晰,增强代码稳定性 在MVC机制下,应用被清晰的分为model,view,controller三个部分,这三个部分分别依次对应了业务逻辑和数据、用户界面、用户请求处理和数据同步。我们知道,对于业务逻辑和数据、用户界面、用户请求处理和数据同步这三部分功能来讲,用户界面发生变动的可能性最大,控制部分变动次之,而业务逻辑是最稳定的。所以这种模块功能的划分有利于在代码修改过程中选取重点,而不是把具有不同功能的代码混杂在一起造成混乱。 便于开发小组进行分工 将应用划分为model,view,controller三个部分,还有利于在项目小组内按照小组成员各自的擅长进行分工,有利于三个部分并行开发、加快项目进度。
2. MVC机制的实现 2.1概述 上一章介绍了MVC的一般概念,这一章将要讲述MVC机制在项目中的具体实现。 2.1.1应用的技术 MVC在某个特定应用上的实现是与该应用的具体技术密切相关的。在网站开发方面,Java是比较成熟和典型的,以一个EJB的项目为例,大部分的系统可能采用Html技术,和J2EE(Java 2,Enterprise Edition)的相关技术,包括:HTML,jsp,JavaBean,Enterprise Java Bean,Servlet。这些技术分布于model,view,controller三个模块之中:view部分用到HTML、JSP和JavaBean技术;controller部分用到Servlet、Stateless Session Bean 、JavaBean 技术;model部分可能用到Entity Bean、Stateless Session Bean、JavaBean技术。 但是,我们在这个项目用的是PHP技术来实现,因此,我们需要作出一些折衷。一方面,要尽量使程序的逻辑实现能够平滑地迁移到另一种技术实现(如J2EE),但同时,我们也要考虑到PHP这种脚本语言的局限性。PHP在对于面向对象的支持上同JAVA这种OO的语言不是同一档次,甚至比PERL都要差得很多。不过,幸运的是,我们的运气还不算太坏,因为PHP里面的PEAR是一个面向对象的扩展。使用PEAR的规范,我们一方面可以使用现有的一些PEAR模块,另一方面,可以使我们的程序是能够按照OO的思想来实现业务逻辑的。因此,我们将废弃过去那种模块化,过程化的编程方式,转变思路,将所有的东西都用类包装起来。 在开始介绍实际的设计之前,我们不妨看看这个项目的需求情况 2.1.2项目需求 这个项目目的很简单,就是要做一个网站的发布系统。发布系统应该能够支持频道,子频道,栏目的划分,特权区的划分,用户角色划分,频道各种模板的定制,文章发布的流程控制…… 更为详细的这里就不再一一叙述了。 2.1.3层次划分 我们的应用不但可以按MVC机制分为model,view,controller三个层次,同时还应该可以按照实现的技术和逻辑关系划分为页面表现模块,业务控制模块,事务管理模块,工具模块4个模块;也可以按照具体的业务划分模块。下面再介绍一下这两种划分方式: 按业务模块划分 按实际业务分为用户管理、文章发布、模板维护、前台显示,系统管理五个部分。每一个部分都对应着发布系统的一个方面。这样,model、view、controller的实现组件就分布于五个业务模块之中。 按实现技术划分 由于我们的实现技术采用了HTML技术和PHP的相关技术,按照这些技术,我们又把整个应用分为页面表现层,业务控制层,事务管理层, 工具模块。这样MVC的3层结构又细化为上面这4个逻辑层(参见下图) 2.1.4 典型的一个用户请求的时序图: 如果你现在仍然对于我所说的这些划分感到很空洞和抽象的话,下面我们来看一个序列图,这个图展示了在MVC下面,一个request是如何响应和实现从数据的操作到页面显示的全过程: 下面分别将分为具体介绍每一个模块的实现方式和在整个应用中的作用 2.2页面表现层 这部分的实现是最为简单的。由模板和使模板实例化的render类来完成。 模板是使用纯HTML来编写,不存在任何的PHP代码和控制逻辑,确切地说,本层不涉及任何商业逻辑,它的用途就是根据选择的模板,和提供的实例的数据,生成一个完整的HTML页面 下图是表现层的一个时序图示意: 首先是AsisstantObj,这是Asisstant类的一个实例(关于Asisstant,后面我们会详细讨论),AsistantObj在init方法中,会分析表现层所要用到的2个XML配置文件,template.xml和render.xml,将相应的template 和render信息装载到系统中,并且会保存起来,在整个session中都可以使用。 其次,由HanlderObj,hanlder类的一个实例,调用Asisstant类的lookupRender来找到某个模板对应的render实例 调用render实例的setTemplate和setRenderData方法,前者是载入并初始化对应的模板文件,后者是设置需要实例化的实际数据 调用render实例的Show方法。在render实例的show方法中,它会调用自身的一个renderIt方法(这个方法在render类里面是一个虚方法,每一个继承render的类都要实现自己的renderIt方法,这个方法里的主要工作就是根据renderdata生成模板的一个实例,具体实现形式参见下面的模板机制),之后,再调用renderObj的show方法将实例化后的页面显示再屏幕上面。 2.2.1模板机制 我们使用PEAR中的IT和ITX模块作为我们的模板引擎,之所以使用它,是因为ITX类是纯PEAR类,在功能上和PHPLIB中的TEMPLATE类似,但是使用上要简单一些。而且ITX有些特性特别适合这种模板的定制,考虑到我们的页面表现没有太特殊的地方,使用ITX能够满足我们的需求。 关于ITX的具体使用细节,可以参考ITX的源代码,这里是它的一个简单的使用方法说明: new IntegratedTemplateExtention($root = "") 构建函数,$root是装载模板文件的目录。注意,这里可能有个BUG,在使用下面的函数装载模板文件的时候,如果装载的文件名中带有路径的话,总是无法找到那个文件,所以我建议你设置$root为模板的目录,然后再使用下面的函数装载模板。 loadTemplatefile($filename, $removeUnknownVariables = true, $removeEmptyBlocks = true) 从指定的文件中加载模板,$removeUnknownVariables表示是否去掉未使用的变量标识,$removeEmptyBlocks表示是否去掉没有使用的块。 setRoot($root) 设置模板的目录 setTemplate($template, $removeUnknownVariables = true, $removeEmptyBlocks = true) 从指定的字符串中加载模板。如果你打算把模板数据存放在数据库中(推荐),这个函数是很有用的。 setCurrentBlock($blockname) 设置当前要解析的块名 setVariable($variable, $value = "") 设置变量标识的值 parseCurrentBlock() 解析当前的块 toUChBlock($block) 设置指定的块,使之即使没有使用,也在输出中显示 parse($block = "__global__", $flag_recursion = false) 解析指定的块 getBlocklist() 得到模板中的块的列表 blockExists($blockname) 判断模板中是否存在指定的块 2.2.2 模板的定义 由于使用了ITX,模板的定义方式很简单,使用 来定义一个需要实例化的HTML块,使用{varname}来定义需要实例化的变量就可以了。对于循环,我们无需在页面上表现,而是放在render类里控制,我们通过选定一个HTML块,然后反复实例化这个块,就可以生成循环的HTML代码了。下面是一个例子: {name}{age}{sex} 这将生成如下的HTML代码: panfan0BOY panfan1BOY panfan2BOY 2.2.3 实例化模板 如在上节所看到的,我们通过给render类设置不同的template和不同的实例化数据,将生成不同的页面。那么,如何将模板和它所对应的render联系起来呢?这是个好问题。为了把复杂的问题简单化,我们没有考虑使用一个通用的能够实例化全部的模板和数据的render,因为这样会造成这个render逻辑非常负责,而是采用许多render,每个render可以实例化一个或者几个相近的模板。每一个模板都有一个它相对应的render类的id,这些定义是我们预先定义好的。我们使用了一个xml文件来定义应用中用到的全部的模板。这个xml文件名叫:template.xml,它的基本结构是这样的:
[1] [2] 下一页
(出处:http://www.sheup.com)
上一页 [1] [2]