1 背景
MVC (Model - View - Controller)架构是一种当前非常流行的架构模式(Architectural Pattern),被广泛使用于传统的桌面GUI(Graphical user interface)、Web应用和手机移动应用中。
- 1979年,MVC的概念被 Trygve Reenskaug 在
Smalltalk
中提出。这种架构模式,极大地降低了GUI应用程序的管理难度,而后被大量用于构建桌面和服务器端应用程序; - 从1996年后,MVC逐渐被广泛应用;
- 2002年,基于
Java
的Web应用框架Spring
引入了MVC的概念; - 2005年,基于
Python
的Django
和基于Ruby
的Rails
也引入了MVC的概念。
2 原始的MVC
在最初以Smalltalk
实现中MVC概念中,MVC是由组合模式(Composite Pattern)、策略模式(Strategy Pattern)和观察者模式(Observer Pattern)三种设计模式组合而成的。
Model-View-Controller (MVC)架构模式中定义一个应用中包括三种角色:模型(Model)、视图(View)和控制器(Controller)。
在MVC架构模式中,不仅定义了各个角色的职能,还明确了各个角色之间相互通信的方式。
关于 user action:
- 在前端框架的 MVC 中,由 View 接收到用户的交互操作,进而View传给Controller。
- 在后端框架的 MVC 中,由 Controller 直接接收 HTTP request,因此 User action 是给 Controller。
- d
2.1 设计模式解析
在原始MVC的这个架构模式中,涉及到了三种设计模式:
- Composite pattern:一个
View
(对应模式中的Composite)是一系列嵌套的View
(对应模式中的Leaf)的组合 - Strategy pattern:一个
Controller
实现了一个到多个View
(分别对应模式中的ConcreteStragegyA,ConcreteStragegyB)。根据实际情况,确定Controller
返回哪一个View
给用户 - Observer pattern: 一个
Model
对象会维护一系列关注Model
状态变化的View
。当该Model
对象(对应模式中的Subject
)状态发生变化时,对应的View
(对应模式中的Observer
)就会收到通知。
2.2 角色职能
Models
Models
层仅仅包括纯粹的业务逻辑(Bussiness Logic),通常还会将数据持久化(即Models
层包括将数据从数据库中存储和提取的逻辑)
而不关心数据在UI界面中如何展示与呈现。
View
View
层关注于数据的呈现,并且提供用户与数据交互(体现为对数据的增删查改)的场所。
View
层通过可视化(visual)的方式(User Interface)将用户感兴趣的数据展示出来,用户可通过与View进行交互实现对数据的增删查改(CURD)或进行相应的业务操作。
Controller
Controller
层作为一个位于View
层与Model
层之间的协调者(intermediary),体现为处理用户交互,即,处理用户的输入和交互,并访问Model
层,获取希望得到的数据,最终选择一个View
,将数据显示出来。
2.3 通信方式
当用户在 View
层中触发一个行为时(比如点击了一个Button),一个事件就产生了,Controller
层会收到这个事件。
此时,Controller
可以调用Model
层,以触发特定的业务逻辑。或者,Controller
也可以直接返回一个View或者在UI界面上作出相应变化。
由于特定View
可以注册成为特定Model
的观察者(Observer),当特定的Model
的状态变化时,特定的View
会收到通知,进而更新自己的UI界面(以告知用户特定的事件发生了)。
2.4 分析
在这个最初的MVC模型中,Model
层与View
层是存在耦合的。
我们指定View
代表UI界面,仅关注于数据的显示和与用户的交互,而Model
代表业务逻辑,仅关注于对业务逻辑的处理。而两者存在耦合,则意味着复用性(Reusability)降低了,同时可维护性(Maintainability)也降低了。
因此,我们渴望存在一种更完美的MVC模式,可以解耦Model
层与View
层。
3 优化后的MVC
同样地,优化后的Model-View-Controller (MVC)架构模式仍然包括三种角色:模型(Model)、视图(View)和控制器(Controller),且三种角色所负责的职能也并没有改变。
然而,在通信方式上进行了优化,即Controller
将完全View
和Model
解耦了。
3.1 角色职能
与上面的原始的MVC
中的角色职能完全相同。
即:
Models
层仅仅包括纯粹的业务逻辑(Bussiness Logic)View
层通过可视化(visual)的方式(User Interface)将用户感兴趣的数据展示出来Controller
层作为一个位于View
层与Model
层之间的协调者(intermediary),以处理用户的输入和交互
3.2 通信方式
当用户在 View
层中触发一个行为(体现为发送一个 Request 到 Controller
的形式)时,Controller
层会访问Model
层(体现为调用Model
层中的方法),紧接着在Model
层中执行相应的业务逻辑处理,并将结果返回给Controller
层。Controller
层在收到结果后,将结果发给View(体现为返回一个Response的形式)。注意,这里Controller
在收到Model
发来的结果后,可能会对这个原始结果进行一定的处理。
View
层与Model
层没有直接的交互。换句话说,View
层只与Controller
层交互,Controller
层只与Model
层交互。
4 MVC在不同框架中的应用
4.1 ASP.NET Web Forms
ASP.NET Web Forms最初的设计思想与Windows Forms类似,即为了简化开发工作,Microsoft为我们提供了很多常用的数据显示与交互控件(比如复选框 CheckList,单选按钮框 RadioButtonList,下拉列表DropDownList等等)。
当我们通过数据绑定(Data Binding)将数据源(比如数据库,XML文件等等)与这些控件绑定后,即可实现无需编写任何代码,就可将数据在Web UI界面中显示出来。
因此,可以看出,View
层与Model
层是存在耦合的(因为View
直接访问了数据持久化层)。
同时,在Controller
管理用户的输入和交互逻辑,需要的时候还会访问Model
层,最终显示一个新的View
或者将处理结果反映在View
中。
因此,Controller
耦合于Model
,也同时耦合于View
。所以ASP.NET Web Forms中的MVC对应于最初提到的原始的MVC。
4.2 ASP.NET MVC
在 Overview of ASP.NET Core MVC 中提到,ASP.NET Core MVC 中的 MVC 交互如下所示:
这与ASP.NET Web Forms中的MVC也是完全相同的,即都是原始的MVC。
而我认为,在实践使用中的 ASP.NET Core MVC,View
往往是不直接访问Model
的,而是访问Controller
。
在此种情况下,View
与Model
就不再存在耦合了。这种实践中的MVC与上文描述的优化后的MVC是一致的。
4.3 Cocoa MVC
4.4 Java JSP
在Java JSP中,MVC 是这样体现的:JSP(view) + Servlet(controller) + JavaBean(model)。
- 当控制器收到来自用户的请求;
- 控制器调用JavaBean完成业务;
- 完成业务后通过控制器跳转JSP页面的方式给用户反馈信息(控制器选择一个JSP(View)给用户作为响应)。
4.5 Spring MVC
4.6 Ruby on Rails
待补充…
5 意义
5.1 前后端并行开发
由于MVC解耦了前端(View)与后端(Model),前端和后端开发者可以并行的进行开发而不会发生相互阻塞(Block)对方工作的情况。
具体来说,当前后端协商并确定相互交互的数据协议(或称为数据结构,比如以一个 XML
或 JSON
的形式),前端开发者可以认为后端开发已经完成,只要根据数据协议传入指定的参数,即可得到希望得到的数据(而无需关注后端的实际开发进度)。相反,后端开发者只要根据数据协议,提供相应的数据(如以 XML
或 JSON
的形式),而无需关注数据在前端以何种形式呈现出来(从而无需关注前端的实际开发进度)。
5.2 代码复用
对于前端页面(View),前端页面仅仅囊括将数据显示出来的职能(而不包括任何将数据进行提取的职能)。因此,前端页面相对更容易被复用。
类似地,对于后端API,如果希望获得特定的数据,只要请求对应的API即可(即使在不同的前端页面)。同理,复用性同样得到了提升。
6 应用
MVC最初推出被应用于桌面GUIs应用,然而在不久之后也被引入到Web应用(Web Application)中。
在Web应用中,又可以将MVC应用在服务端(Server Side)或客户端(Client Side)中。
6.1 应用于服务端
用户通过浏览器在View
中触发一个request请求(比如,以GET
或POST
的形式)发送到服务端的Controller
,Controller
调用Model
以完成业务逻辑的处理并得到结果,并将结果返回给客户端的View
,View
最终将获得的结果显示出来。
将MVC应用于服务端的框架包括Django
、Rails
、ASP.NET MVC
。
6.2 应用于客户端
而在 AngularJS
、 EmberJS
、 JavaScriptMVC
和 Backbone
等框架中,所有MVC组件的交互过程仅仅只在客户端发生。
Reference
- A note on DynaBook requirements
- Model View Controller History
- The Evolution of MVC
- Trygve Reenskaug - The original MVC reports
- Applications Programming in Smalltalk-80 (TM): How to use Model-View-Controller (MVC)
- Wikipedia - MVC
- Cocoa Core Competencies - MVC
- Concepts in Objective-C Programming - MVC
- ASP.NET MVC 4 Overview - Web Froms
- 浅析前端开发中的 MVC/MVP/MVVM 模式 - https://juejin.im/post/593021272f301e0058273468