MVC是一种设计模式(Design pattern),也就是一种解决问题的方法和思路, 是上世纪80年代提出的,到如今已经很有历史了。 MVC的意义在于指导开发者将数据与表现解耦,提升代码,特别是模型部分代码的复用性。php
MVC不只仅存在于Web设计中,在桌面程序开发中也是一种常见的方法。MVC的出现已经有一段历史了。 记得我最先了解到MVC的时候,是在Microsoft的Visual C++ 中的MFC中。 当时年少无知,觉得是MFC中特有的东西。后来随之不断学习,才发现本身的天真。 因此说,学得越多,就越以为本身无知。越以为本身无知,就越懂得敬畏和谦逊。 从这个角度讲,同窗们,最好不要看不起谦逊的人。前端
有个这么一个段子,说一天A君在圈内聚会时,朋友介绍了另外一我的B君互相认识。 聚会场合嘛,这很正常,也很广泛。因而AB君小聊了一下。按国人的习惯,A君就问了“先生在哪高就?”。 B君只说了句,“谈不上高就,炒炒股。” “哦,原来是炒股的。”A君心想,虽没以为什么不对,但心理以为B有点low,只是没说破,也没表现出来。 事后了一段时间,一次偶然机会,发现原来B君是国内某上市公司的二股东,身家过亿。 人家没说慌,确实是炒股的……程序员
话说远了,咱们还说正题。MVC是三个单词的缩写:Model, View, Controller。 MVC是一种设计模式,目前几乎全部的Web开发框架都创建在MVC模式之上。 固然,最近几年也出现了一些诸如MVP, MVVM之类的新的设计模式。 但从技术的成熟程度和使用的普遍程度来说,MVC还是主流。ajax
Yii是一个Web框架,从Web开发的分工来说,Yii的开发工做中,承担后端的内容多一些,毕竟主要就是PHP开发。 前端主要是在HTML、JavaScript、CSS上进行开发,而后经过Yii把前端的内容管起来,如经过Assets等。 这一章要讲的MVC,主要是针对后端的。 前端的MVC严格来说不属于Yii的范畴,这里咱们就不做过多介绍。 若是想了解前端的MVC,能够看看Backbone.js Angular.js等前端框架。数据库
MVC是模型(Model)、视图(View)、控制器(Controller)3个单词的缩写。 下面咱们从这3个方面来说解MVC中的三个要素。后端
对于MVC中三者的划分并无十分明晰的定义和界线。MVC设计模式只是一种指导思想, 让你按照model, view, controller三个方面来描述你的应用,并经过三者的交互,使应用功能得以正常运转。设计模式
其中,View的部分比较明确,就是负责显示嘛。一切与显示界面无关的东西,都不该该出如今View里面。 所以,View中通常不会出现复杂的判断语句,不会出现复杂的运算过程。 对于PHP的Web应用而言,毫无疑问,HTML是View中的主要内容。这是关于View的几个原则:数组
对于Model而言,最主要就是保存事物的信息,表征事物的行为和对他能够进行的操做。 好比,Post类必然有一个用于保存博客文章标题的title属性,必然有一个删除的操做,这都是Model的内容。 如下是关于Model的几个原则:浏览器
对于Controller,主要是响应用户请求,决定使用什么视图,须要准备什么数据用来显示。 如下是有关Controller的设计原则:前端框架
在MVC中,Model排第一,是有必定暗示的。一是Model是整个架构中,代码量最大,复用程度最高, 也是最体现程序员设计功力的地方。 二是View和Controller相对于Model而言,在实际开发中,复用程度不高,逻辑复杂程度较低。 能够说,Model设计得好,整个MVC就好,应用开发起就顺。
所以,这一节将以Model为核心,来说MVC的设计。 实话说,MVC尽管提出了Model View Controller的划分思想,但到了具体实操中,并非很好把握的。 下面介绍的设计参考,也仅仅是我的在实际项目中的一些体会和想法,仅做参考。 在具体设计中,能够后把握这么几点:
应用当中涉及到的全部业务对象都应尽量抽像成Model。 如,博客系统当中,文章要抽象成Post,评论要抽象成Comment。 而相关的业务逻辑,如发布新文章能够用 Post::create() ,删除评论能够用 Comment::delete() 。 这样子整个应用就显得很清晰明了。
在一个应用中,特别是对于大型复杂应用,Model间关系可能比较复杂。在构造应用时,特别是基础Model时, 要从足够小的粒度来设计。 此时,就要考虑采起继承、封装等措施了。 好比,一个博客文章Post,通常包含了若干标签,在页上通常写在做者、日期等Post字段的旁边。 从逻辑上来看,把标签做为Post的一个属性,是说得通的。 可是若是把标签做为一个属性像标题、正文等字段同样依附于Post。那么在有的功能上,实现起来是有难度的。 好比,客户要求,当一个Post含有标签 “yii, model” 时,能够点击 “yii” , 而后系统列出全部具标签中含有 “yii” 的文章。
为了实现这个功能,正确的设计是单独将标签抽象成Tag。这样,Post和Tag是多对多的关系, 即一个Post有多个Tag,一个Tag也对应多个Post。这个多对多关系能够经过一张数据表 tbl_post_tag 来表示。 接下来,为Post增长 Post::getTags() 方法,并经过 tbl_post_tag 表来查询当前Post的全部标签。 同时,为Tag增长 Tag::getPosts() 方法,也经过 tbl_post_tag 表来查询当前Tag对应的文章。 这样,就具有了实现客户要求的新功能的基础。
所以,在Model设计上,要以尽可能小的粒度进行设计。通常而言,粒度越小,复用的可能性就越高。
有的读者可能会问了,既然要求粒度尽量地小,那么,Post是否是也应当再细化,把段落抽象为Model? 是否有这个必要,看客户需求。通常状况确实没有这必要,若是这么作,那是否是再以句子为单位进行抽象? 但若是客户要求这个博客系统的评论是针对段落进行的评论的, 要将评论显示在对应的段落旁边,甚至显示每一个段落评论人次等功能。那么就须要把段落抽象成Model了。
从设计流程上,数据库结构设计与Model的设计是紧密相关的。先有数据库结构设计,后有Model设计。 在设计数据库结构的时候,也是在设计Model。 通常而言,最单元、粒度最小的Model就是根据每一个数据库表所生成的Model,这每每是个Active Record。
好比标签的问题,在数据库存储过程当中,Post和Tag是分开存的,并且这两个表的字段,没有冗余。 tbl_post_tag 表也只记录他们的ID,没有实质内容。
在获取数据渲染视图,向用户展示时,这两个Model及他们的字段,是彻底够用,且没有冗余的。
那么,能不能说 Post 和 Tag 这两个Model是够用的呢?显然还不够。
当用户在建立文章、修改文章、审核文章时,须要采用一个表单来显示来收集用户输入。 其中,对于标签的采集,通常是一个长条的文本框,让用户一次性输入多个标签,并以 , 等进行分隔的。
可是,这个文本框没有一个字段与之进行对应。咱们也没办法对这个字段的用户输入进行任何的验证、预处理。
所以,Post的功能是不够用的。不够用怎么办?那就加吧。但直接在 Post 里面加个 public $tagString 并很差。 毕竟只是在使用表单时,才会有这个问题,其余场合,这个字段是没用的。
这种状况下,通常使用继承:
1 2 3 4 5 6 |
public class PostForm extends Post { public $tagString; ... ... }
|
这样,当控制器发现用户在建立、修改、审核文章时,可使用 PostForm Model来渲染视图了, 而其余场合则仍使用Post。这样就在须要时,增长了一个 tagString 的字段用于收集用户输入的标签。
在具体设计过程当中,因为Model自己就会包含不少代码,所以,要多使用这继承等手段,把代码组织好。
因为Model的代码量比较大,又集中了大量的逻辑,所以,会在一个Model中有大量的方法。仍然以Post为例, 会涉及到建立、审核、发布、回收等流程,相关的方法比较多,在命名上要用心。 可能会涉及到的、名字又比较接近的方法就有:
这里只是一些获取其余Post的方法,命名比较合理,一看就知道意思。 并且所有写成getter的形式,可使用读取属性的方式进行访问。
不仅仅是在Model方法的命名上要用心, 在变量名、类名、方法名等的命名上,也要养成习惯,造成规律。 不要图一时之快,胡乱起名。不然,出来混,早晚要还的。
从MVC的起源来说,是从桌面应用的开发中发展起来的。从本质来说,这是一种解决问题的思路和办法。 从实践来说,这是一种久经考验的有效方式。可是如开头咱们讲的,Yii更多的是侧重于后端。 对于Web应用而言,包含Yii在内的许多Web开发框架,都是没有办法知道用户的操做,如鼠标、键盘等操做的。 Web应用想要了解用户的操做,只能依靠用户发送Request。 而对于鼠标、键盘等的响应,只能依靠前端技术,如JavaScript等来实现。
再加上这几年来Web浏览器的功能日臻强大。所以,Web应用开发出现了一个新的发展苗头,就是功能从后端往前端转移。
在前端,经过JavaScript捕获用户操做,进行相应处理。 或是发送回后端获取响应后处理,如经过ajax请求后端数据,实现无刷新的局部页面更新,向用户进行反馈; 或直接在前端由浏览器进行处理,如使用backbone.js、Angular.js等前端框架的数据绑定功能等。 这些都使得Web应用表现得愈来愈像桌面应用。
后端MVC也在为先后端的发展而改变。 Controller的功能更多的变成了识别是ajax请求仍是普通请求, 并根据请求的不一样采起相应的视图渲染方式。对于普通请求,正常渲染视图,输出HTML。 对于ajax请求,则返回局部渲染视图,输出HTML片断。有的甚至输出XML或者JSON。 惟一在大潮流中,巍然不动的,仍是咱们的大Model。