几乎全部应用系统都是由这三部分组成:表示企业数据和业务规则的数据,用来展现数据的,用户看到并与之交互的界面,负责转发请求,对请求的处理;协调数据和展现的逻辑。在MVC出现以前,这三部分都是写在一块儿的,是耦合的,这对软件工程是很差的。设计模式
1979年,Trygve Reenskaug在Smalltalk-80系统上首次提出了MVC的概念,最初的时候叫作Model-View-Controller-Editor。1994年,Gof(Gang of Four)在 Design Patterns: Elements of Reusable Object-Oriented Software 一书中对MVC模式作了深刻的解析。架构
Trygve Reenskaug最初提出MVC的目的是为了把数据(Model
)和视图(View
)分离开来,而后用控制器(Controller
)做胶水来粘合M和V之间的关系。很显然,这样作的目的是为了实现注意点分离这样一个更高层次的设计理念,View
就只负责视图相关的东西,Model
就只负责描述数据模型,Controller
负责总控,各自协做。app
经过把职责、性质相近的成分归结在一块儿,不相近的进行隔离,MVC将系统分解为模型、视图、控制器三部分,每一部分都相对独立,职责单一,在实现过程当中能够专一于自身的核心逻辑。MVC是对系统复杂性的一种合理的梳理与切分。框架
Model对view和controller均可知,view对controller可知,controller对谁都不可知。ide
这里为了容易理解,我想用咱们实验室三个屋来打个比方,小屋是view,中屋是controller,大屋是model。函数
用户请求、试图选择:小屋不认识中屋,可是中屋认识小屋,小屋一旦有需求,中屋就会默默地知足他的要求,好比:小屋的贾老师大喊一声“把三木球拉出去”,中屋就来了一我的把三木球拉了出去。this
状态查询:小屋认识大屋,小屋想知道大屋的郭师兄今天穿了件什么颜色的衣服,就跑去看了看,哦,原来郭师兄穿了件绿色的衣服。编码
用户请求、状态改变、通知改变:贾老师大喊一声“给郭师兄换件红色的衣服”,隔壁屋的一我的就去给他换了,郭师兄换完衣服,开心地大喊了一句“我换了件红色的衣服!”。spa
其实这里,我对状态的理解仍是有些模糊,暂且把它当作数据,好比登陆,某种角色的用户登陆后,controller会告诉model改变状态,而后通知给view,也就是展现给该角色的用户相应的数据。设计
GoF (Gang of Four,四人组, 《Design Patterns: Elements of Reusable Object-Oriented Software》/《设计模式》一书的做者:Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides)并无把MVC说起为一种设计模式,而是把它当作"一组用于构建用户界面的类集合"。在他们看来,它实际上是其它两个个经典的设计模式的演变:观察者模式(Observer)(Pub/Sub)和策略模式(Strategy)。
正如咱们所讨论的,models表示应用的数据,而views处理屏幕上展示给用户的内容。为此,MVC在核心通信上基于推送/订阅模型。
view: models[0...n]; callbackModelEvents[0...n]; for(model 0...n) for(model[i].Event(0...n)) this.on(Events[j], callbackModelEvent[k]);
View(订阅者)注册了一组model和model对应的事件的处理函数,当model(发布者)一旦发布了消息,view就会接收。
View和controller同上。
Extjs这个框架是典型的MVC模式,它帮咱们完成了MVC的大部分工做,为了体现MVC模式,提供给咱们这样的接口,固然,咱们用户的主要代码就是写在这里的。
这是ExtJs4.2的工程文件目录,咱们的代码就写在controller、model、store、view这四个文件夹下,接下来,咱们看一下Ext代码是怎么写的。
Ext.define("Srims.view.patent.PatentList", { extend: 'Ext.grid.Panel', store: [patent.patents], …… });
在view中,咱们能够配置当前view对应的store(即数据),当数据更新时,从model发出消息,展现在view中,固然,咱们须要配置这么一行代码,剩下的框架已经帮咱们作好了。
Ext. define('Srims.controller.patent.patentList', { extend: 'Ext.app.Controller', views: ['patent.patentList'], model:[patent.patents], …… 'patentlist button[itemId=btnDeletePatent]': { //删除按钮点击响应 click: function (button, e) { Ext.MessageBox.confirm('确认', '确认删除选中记录么?', function (btn) { if (btn == 'yes') { var panel = button.up('panel'); var selectionRecord = panel.getSelectionModel().getSelection()[0]; var store = panel.getStore(); store.remove(selectionRecord); } }, this); …… } }, …… });
在controller中,能够配置当前controller对应的view、model,在方法中也能够对view对应的store操做,也能够直接建立store(model)的实例,对其操做。
经过这样配置,能够实现观察者模式。
在Ext中,view和controller是多对多的关系,好比,controller对它注册的多个view进行消息响应或者操做,假如要选择view1通常经过get方法,就是get加view1做为方法名,使用的,这样看上去是没问题的。
可是Ext是基于类的,实际应用中,咱们一般是这样的,因为不少view长得很像甚至相同,咱们习惯复用同一个view类,这样,一个view类对应着多个实例。咱们在controller中的全部方法都是针对他对应的view类的,当咱们建立了一个controller实例,经过该类中的方法找到对应的view类,来操做这个view类对应的view实例,这时候,一个view对应着多个实例,操做就会产生混乱。
固然,只要咱们在编码是注意经过controller中适当处理逻辑,在view中适当添加标志位,混乱和冲突也是能够解决的。因此从此,适当复用而且提升编码能力,也是没问题的。
在传统的MVC架构里包括Extjs,一个controller可能有多个方法,每一个方法每每对应一个user action,所以,一个controller每每对应多个user action。传统MVC架构里将一个user action委派到某个controller的某个方法的过程。
目前,不少平台的主流MVC框架在设计上都引入了command模式,command模式的引入改变了传统MVC框架的结构,受冲击最大的就是 controller。
在基于command的MVC架构里,一个command每每只对应一个user action,在该架构里变成了将useraction与command一一绑定的过程。
主流MVC框架向command转型一个很是重要的缘由就是:因为缺乏合理的组织依据,controller的粒度很难拿捏。
controller不一样于view与model,view与model都有各自自然的粒度组织依据,view的组织粒度直接承袭用户界面设计,model的组织粒度则是依据某种分析设计思想(如OOA/D)进行领域建模的结果,controller须要同时协调view与model,可是view与model的组织结构和粒度都是不对等的,这就使得controller面临一个"在多大视图范围内沟通与协调多少领域对象"的问题,因为找不出合理的组织依据,设计者在设计controller时每每感到无所适从。
Extjs虽然在这方面考虑欠佳,但咱们能作的就是遵循良好的设计原则,对某些较"大"的user action方法进行分解,从中抽离出一些可复用的部分封装成一些较"小"的方法,尽可能减少代码的冗余。