+关注继续查看

我的需求

  • 晚上练完车之后,之前参考我毕设的一个小伙伴要答辩,问了我一个问题,结果问的一下不知道怎么回答.... 以下是我回答他问题的答案 :所以在回答完他之后,赶快整理一波..

在这里插入图片描述

我需要解决的问题

  • MVVM到底是个什么东东,和前后端有没有关系,它和MVC区别是啥,有啥优势。

我是这样做的

  • 百度 寻找,找了一些关于MVVM论文,博客,梳理出自己的答案。
  • 嗯,资源比较零散,准确性有待考量, 所以不对的地方请小伙伴指出来

爱自己,是终生浪漫的开始 ------王尔德


对于MVC想来小伙伴是不陌生的,但是网上的资源各抒己见....我也整的晕头转向的,可能有 前(后)端 ,有 胖(瘦)客户端 框架应用,具体还有细微的差异。

If you put ten software architects into a room and have them discuss what the Model-View-Controller pattern is, you will end up with twelve different opinions. --Josh Smith 1
如果你把10个软件架构师放在一个房间里,让他们讨论模型-视图-控制器模式是什么,你最终会得到12种不同的观点。

我们这里讨论的 MVC MVVM 是以 BS架构 为基础的 java Web 中的应用,因为博主只接触了这方面的,关于网上提到的 IOS 和一些 客户端 框架,没有接触过。本博客也不涉及。所以如果听都没听过 java Web 的,或者没了解过 Web框架 的小伙伴个人感觉这篇博客不太适合,不太建议继续读下去。

我们先看看MVVM吧!嘻嘻 ^ _ ^

MVVM 名词解释:

MVVM Model-View-ViewModel 的简写。它本质上就是 MVC 的改进版。MVVM 就是将其中的 View的状态和行为抽象化 ,让我们将 视图 UI 业务逻辑 分开。当然这些事 ViewModel 已经帮我们做了,它可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑。 MVVM(Model-View-ViewModel)框架 的由来便是 MVP(Model-View-Presenter)模式 WPF 结合的应用方式时发展演变过来的一种 新型架构框架 。它立足于原有 MVP 框架并且把 WPF 的新特性糅合进去,以应对客户日益复杂的需求变化。 2

MVVM upright=1.5 MVVM(Model–view–viewmodel) 是一种 软件架构模式 MVVM 有助于将 图形用户界面的开发 business logic (业务逻辑)或 后端逻辑 (数据模型)的开发 分离 开来,这是通过置标语言或GUI代码实现的。MVVM的视图模型是一个 值转换器 , 这意味着 视图模型 负责从 模型 暴露(转换)数据对象 ,以便轻 松管理和呈现对象 。在这方面, 视图模型 视图 做得更多,并且处理大部分 视图 显示逻辑 。 视图模型可以实现 中介者模式 ,组织对视图所支持的用例集(Model)的后端逻辑的访问。 3

MVVM 的发展历程

MVVM 马丁·福勒 PM(Presentation Model)设计模式 的变体。 MVVM 以相同的方式 抽象 视图的状态和行为 , 但 PM 不依赖于特定用户界面平台 的方式抽象出 视图 (建立了视图模型)。 MVVM PM 都来自 MVC模式 MVVM 由微软架构师 Ken Cooper Ted Peters 开发,通过利用 WPF(微软.NET图形系统) Silverlight(WPF的互联网应用衍生品) 的特性来 简化用户界面 事件驱动程式设计 。 微软的WPF和Silverlight架构师之一 John Gossman 2005 年在他的博客上发表了 MVVM 。 MVVM也被称为 model-view-binder ,特别是在不涉及 .NET平台 的实现中。ZK(Java写的一个Web应用框架)和KnockoutJS(一个JavaScript库)使用 model-view-binder 3

MVC到MVVM 的发展历程

二十世纪八十年代 施乐帕克实验室 提出了 MVC 的概念,MVC的全称即 Model-View-Controller ,是 模型(model) 视图(view) 控制器(controller) 的缩写“…,它是一种 客户端软件开发框架 4 ,个人认为,其实最初的 Java Web 来讲, Model2 Servlet+JSP 也是用的这个结构,所以说 Model2(MVC) 它相对已 Model1(Javabean+JSP) 来讲,已经实现了 View Model 的部分解耦,但是不彻底,如图

Java Web Model2
view 负责显示, Model 负责提供数据, Controller 负责逻辑的处理,其实现的流程大概是: 4

  • (1)当用户需要发送请求时,首先是在View发送请求,由View将指令传送到Controller里。
  • (2)Controller接收到指令之后,先完成所需要的业务逻辑,然后要求Model根据业务逻辑改变状态;
  • (3)Model将新的数据发送给View,View则根据新的数据更新视图,从而用户的请求得到反馈。

MVC 框架中, View 是可以直接访问 Model 的(JSP里直接使用 JavaBean ),这样不可避免的使 View 里面也需要包括一些 业务逻辑 ,同时还需要 Model 保持不变,而 Model 又对应着多个不同的显示(View),所以总体说来就是,在MVC模型里面, Model 不依赖 View ,但是 View 是依赖于 Model 的。这样就导致更改 View 比较困难,且 业务无法重用 。从而 MVC框架的弊端就显现出来 4 ,这也是使用 Servlet+JSP 的弊端。前后端没有解耦, Model View 没有彻底解耦。

为了解决 MVC 框架中 View Model 联系紧密的问题,开发者研究开发了 MVP 模式, MVP Model-View-Presenter ,即把MVC中的 Controller 换成了 Presenter ,目的就是为了完全切断 View Model 之间的联系,在MVP模式中, View 负责 视图的显示 , Model 负责 提供数据 Presenter 则主要负责 逻辑业务 的处理。 4

有些 SSM+JSP 的开发方式也是基于这种,我之前的公司就这样写,前后端不分离使用的 JSP ,但是交互全是 Ajax ,传递的全是 JSON ,也没有返回 ModelAndView ,个人感觉这里其实是使用了 MVP 的模式。以前后端 不分离 的方式 丢弃模板引擎的服务端渲染 ,追求前后端 分离 彻底解耦了View和Model 。看上去怪怪的,其实有时候项目开发更多的是和 业务 体量 成本 效益 等有关系,综合考虑,选最合适,不一定要按照 常规 构建方式 考虑,比如正常思考可能 不分离 是为了 服务端渲染 首屏快载 SEO 等,分离是为了 降低服务器压力 接口复用 ,前后端 工作职责解耦 .

对于 SSM + 模板引擎 的开发方式

  • 如何是返回 Modelandview 的话,那 缺点 就是 后端路由 ,前后端没有 彻底解耦 ,优点就是 服务端渲染 ,返回的是整个 构建好的页面 .
  • 如果返回 JSON 的话,那优点就是 前后端彻底解耦 接口复用 ,但是没有利用模板引擎的 服务端渲染
  • 如果体量很大,那前后端是两个人写,那使用 Modelandview 的方式就很麻烦,需要 接口协调 ,而且工作 职责不清晰 。会浪费好多时间。JSON就方便很多。
  • 如果体量不是他大,前端的东西也不是特别多,考虑成本问题,前后端一个人写,那 Modelandview 就很合适,节省了接口协调,对接等时间成本问题。

在这里插入图片描述
MVP 框架中, View 无法直接再与 Model 交互, View Model 之间的通信都是通过 Presenter 进行完成的,所有的交互都在 Presenter 内部发生,即由 Presenter 充当了 View Model 的桥梁,做到 View-Model 之间通信的 完全隔离 Presenter 完全把 Model View 进行分离,将主要的程序逻辑放在Presenter里实现。 4

Presenter View 也是没有直接相关联的,而是通过已定义的 接口进行交互 ,从而使得在变更 View 的时候可以保持 Presenter 的不变,即保证了 Presenter 的可重用性(接口的复用性),同时也解决了 MVC 框架中的 View Model 关联紧密的问题。 4

这样之后,对于 Web 项目来讲,前后端都是通过数据进行交互,那 路由 怎么处理,前端只能实现简单一部分跳转,涉及到复杂的需要 通过Controller(Presenter)来处理的路由 怎么处理,或者带状态的路由如何跳转,即 Controller无法控制使用那个View 。个人感觉, Web 系统来讲这个时候 完全的前后端分离 可能不是适合所有项目,而且分离之后留给 前端要解决的问题 可能也不是能很好的解决。所以这个时候....

有个叫 Rod Johnson 带领一帮人搞出的 SpringMVC ,不像桌面应用的 MVC , 这里的Model没法给View 发通知。 5 也不像 MVP , 这里的 Controller 可以控制 View 来实现路由。即前后后端没有分离,但是将原来的 View的构建解耦 了。由 模板 数据 构成:

public class MyGlobalException {
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public ModelAndView customException(MaxUploadSizeExceededException e) {
        ModelAndView mv = new ModelAndView("javaboy");
        mv.addObject("error", e.getMessage());
        return mv;
}

即降低了 View Model 耦合,同时又实现了 后端路由
在这里插入图片描述
对于大型项目而言, 前端 的东西原来越多,造成 服务端 的压力越来越大,而且由于 MVP 的出现,逐渐向 前后端分离 靠拢,分离之后,View分担 服务端 的压力,或者说是 浏览器 分担了 服务器 压力,包括页面渲染,路由等问题,这时侯MVVM出现了..( 这里是自己猜的,没找到相关资料

MVVM 框架便是 前后端分离框架发展史 上的一次思想的完全变革。它是将 数据模型双向绑定 的思想作为变革的 核心 ,即 View 的变动,自动反映在 ViewModel 上面,而 ViewModel 的变动也会随即反映在 View 上面,从而实现 数据与模型的双向绑定 4

MVVM 框架中, View 用于发送用户的 交互请求 ,之后将用户请求转交给 ViewModel ViewModel 即可根据用户请求操作 Model 数据更新,待 Model 数据更新完毕,便会通知 ViewModel 数据发生了变化,然后 ViewModel 就会即刻更新 View 数据,完成视图的更新,从而完成用户的请求。 4
在这里插入图片描述

虽然 MVVM 框架和之前的 MVC MVP 模式的目的相同,即完成 视图(View)和模型(Model)的分离 ,但它却有着明显的优势。 4

  • 首先,MVVM框架中的 View 完全可以独立于 Model 发生 变化和修改 ,彻底解耦,View发生变化时Model可以不变,同样,当Model发生变化时View也可以不变化,并且一个 ViewModel 可以绑定到多个不同的 View 上面,这就体现了 MVVM框架的低耦合性
  • 其次,绑定在一个 ViewModel 上面的多个 View 都可以使用 ViewModel 里面的视图逻辑,完成了框架可重用性的特性。除此之外, MVVM框架 还具有 可独立开发 可测试 等特性,把框架作用发挥到最大化,也因此成为了开发者们青睐的框架。。

对于 MVVM 这种模式主要用于构建 基于事件驱动的 UI 平台 ,对于前端开发领域中 数据与界面相混合 的情况特别适用 6 ,其中

  • Model 仅仅只是代表应用程序所需的数据信息,它 不关注 任何行为;
  • View 是软件中与用户进行直接交互的部分,它需要响应 ViewModel 的事件并格式化数据, 不负责 控制应用的状态;
  • ViewModel 用于 封装业务逻辑层 ,这点类似于 MVC 模式中的控制器,它 控制View 的很多显示逻辑,它可以把 数据模型 的变化 传递 视图 ,也可以把视图中数据的变化传递给数据模型,即在 Model 和View 之间建立了双向绑定。
Vue与MVVM

我第一次看到 MVVM 是因为 Vue ,相信好多小伙伴也是 Vue 认识 MVVM 架构模式。Vue官网中讲到: 虽然没有完全遵循 MVVM 模型,但是 Vue 的设计也受到了它的启发。因此在文档中经常会使用 vm (ViewModel 的缩写) 这个变量名表示组件实例
在这里插入图片描述
通过 双向数据绑定 连接 视图 层和 数据 ,而实际的 界面 UI 操作 DOM 操作 )被封装成 对应的指令 (Directives)和 过滤器 (Filters)

MVVM原理: 7

实现 数据绑定 的做法有大致如下几种:

  • 脏值检查(angular.js) : angular.js 是通过 脏值检测 的方式比对数据是否有 变更 ,来决定是否 更新视图 ,最简单的方式就是通过 setInterval() 定时 轮询检测 数据变动,angular只有在指定的 事件触发时 进入 脏值检测 .

    • DOM 事件,譬如用户输入文本,点击按钮等。( ng-click )
    • XHR 响应事件 ( $http )
    • 浏览器 Location 变更事件 ( $location )
    • Timer 事件 ( $timeout , $interval )
    • 执行 $digest() $apply()
  • 数据劫持(vue.js) : 数据劫持 ,指的是在 访问 或者 修改 对象的某个属性时,通过一段代码 拦截 这个行为,进行 额外的操作 或者 修改返回结果 。简单地说,就是当我们 触发函数 的时候 动一些手脚做点我们自己想做的事情,也就是所谓的 "劫持"操作

    • 在Vue中其实就是通过 Object.defineProperty 来劫持对象属性的 setter和getter 操作,并“种下”一个 监听器 ,当数据发生变化的时候发出通知: Object.defineProperty(obj,prop,descriptor)

参数:
obj:目标对象
prop:需要定义的属性或方法的名称
descriptor:目标属性所拥有的特性
可供定义的特性列表:
value:属性的值
writable:如果为false,属性的值就不能被重写。
get: 一旦目标属性被访问就会调回此方法,并将此方法的运算结果返回用户。
set:一旦目标属性被赋值,就会调回此方法。
configurable:如果为false,则任何尝试删除目标属性或修改属性性以下特性(writable, configurable, enumerable)的行为将被无效化。
enumerable:是否能在for...in循环中遍历出来或在Object.keys中列举出来。

+ >`Proxy数据代理`:Proxy 可以被认为是` Object.defineProperty() 的升级版`。外界对`某个对象的访问`,都必须经过这层`拦截`。因此它是针对 整个`对象`,而不是 对象的某个`属性`。
var data = {name:'test'}
Object.keys(data).forEach(function(key){
    Object.defineProperty(data,key,{
        enumerable:true,
        configurable:true,
        get:function(){
            console.log('get');
        set:function(newValue){
            console.log('监听到数据发生了变化');
            document.getElementById(‘myText’).value=newValue;
document.getElementById(‘myText’).addEventListener(‘keyup’,function(e){
 data.name=e.target.value; // 监听 View 的变化,同步更新 Model
data.name //控制台会打印出 “get”
data.name = 'hxx' //控制台会打印出 "监听到数据发生了变化"
var arr = [1,2,3]
var handle = {
    //target目标对象 key属性名 receiver实际接受的对象
    get(target,key,receiver) {
        console.log(`get ${key}`)
        // Reflect相当于映射到目标对象上
        return Reflect.get(target,key,receiver)
    set(target,key,value,receiver) {
        console.log(`set ${key}`)
        return Reflect.set(target,key,value,receiver)
//arr要拦截的对象,handle定义拦截行为
var proxy = new Proxy(arr,handle)
proxy.push(4) //可以翻到控制台测试一下会打印出什么
  • 发布者-订阅者模式(backbone.js) :
上述介绍了简单的 一对一双向绑定 的实现,即一个 数据模型 只与一个 视图 进行绑定。当多个 View 与一个 Model 进行绑定时,每次更新 Model 时需要在 Model set 访问器属性中更新多个 View ,这样硬编码的方式不利于 后期的维护 。为了解决 硬编码带来的耦合性过强 的问题,在在实际实现中,需要使用到设计模式中的 发布 - 订阅模式

发布 - 订阅模式 (又称 观察者 模式)是一种常用的设计模式,该模式包含 发布者 订阅者 两种角色。可以让 多个订阅者 订阅同 一个发布者 发布的主题,当发布者的主题发生变化时,对外发送一个通知,所有订阅了该主题的订阅者都会接收到更新的消息。因此,观察者模式定义的是 一种一对多的关系 。发布 - 订阅模式非常适合于 MVVM 双向绑定中多个视图绑定到同一个数据模型的情形。

实现双向数据绑定步骤 7

要实现 mvvm 的双向绑定,就必须要实现以下几点:

  1. 实现一个 指令解析器Compile ,对每个元素节点的指令进行扫描和解析,根据 指令模板 替换数据,以及 绑定 相应的 更新函数
  2. 实现一个 数据监听器Observer ,能够对数据对象的所有属性进行监听,如有变动可拿到最新值并 通知订阅者(Dep)
  3. 实现一个 Watcher ,Watcher是订阅 - 发布模式中订阅者的实现,作为连接 Observer Compile 的桥梁,能够订阅并收到每个属性变动的通知, 执行指令 绑定的相应回函数 (发布),从而 更新视图
  4. MVVM入口函数,整合以上三者

在这里插入图片描述
新建 一个 Vue 对象 时,框架进入 初始化 阶段。Vue 在初始化阶段主要执行两个操作:

  • 第一个是 遍历系统中数据 的所有属性,来对各个属性的 变化添加监听
  • 第二个操作是利用 指令编译器 Compile 对视图中绑定的指令进行扫描 进行视图的初始化 ,然后订阅 Watcher 更新视图 ,此时 Watcher 会将自己添加到 消息订阅器Dep 中。至此,Vue的初始化过程结束。

在系统运行过程中,一旦系统中的数据模型发生了变化, 观察者 Observer 的 setter 访问器属性就会被触发,此时消息 订阅中心 Dep 会遍历它所维护的所有 订阅者 ,对于每一个订阅了该数据的 对象 ,向它发出一个 更新通知 ,订阅者收到通知后就会对 视图 进行相应的更新。以上过程不断往复循环,这就是 MVVM 模式在 Vue.js 中的运行原理。

<!DOCTYPE html>
<html lang="en">
    <meta charset="UTF-8">
    <title>Two-way data-binding</title>
</head>
    <div id="app">
        <input type="text" v-model="text">
        {{ text }}
    <script>
        function observe (obj, vm) {
            Object.keys(obj).forEach(function (key) {
                defineReactive(vm, key, obj[key]);
        function defineReactive (obj, key, val) {
            var dep = new Dep();
            Object.defineProperty(obj, key, {
                get: function () {
                    if (Dep.target) dep.addSub(Dep.target);
                    return val
                set: function (newVal) {
                    if (newVal === val) return
                    val = newVal;
                    dep.notify();
        function nodeToFragment (node, vm) {
            var flag = document.createDocumentFragment();
            var child;
            while (child = node.firstChild) {
                compile(child, vm);
                flag.appendChild(child);
            return flag;
        function compile (node, vm) {
            var reg = /\{\{(.*)\}\}/;
            // 节点类型为元素
            if (node.nodeType === 1) {
                var attr = node.attributes;
                // 解析属性
                for (var i = 0; i < attr.length; i++) {
                    if (attr[i].nodeName == 'v-model') {
                        var name = attr[i].nodeValue; // 获取v-model绑定的属性名
                        node.addEventListener('input', function (e) {
                            // 给相应的data属性赋值,进而触发该属性的set方法
                            vm[name] = e.target.value;
                        node.value = vm[name]; // 将data的值赋给该node
                        node.removeAttribute('v-model');
                new Watcher(vm, node, name, 'input');
            // 节点类型为text
            if (node.nodeType === 3) {
                if (reg.test(node.nodeValue)) {
                    var name = RegExp.$1; // 获取匹配到的字符串
                    name = name.trim();
                    new Watcher(vm, node, name, 'text');
        function Watcher (vm, node, name, nodeType) {
        //  this为watcher函数
            Dep.target = this;
        //  console.log(this);
            this.name = name;
            this.node = node;
            this.vm = vm;
            this.nodeType = nodeType;
            this.update();
            Dep.target = null;
        Watcher.prototype = {
            update: function () {
                this.get();
                if (this.nodeType == 'text') {
                    this.node.nodeValue = this.value;
                if (this.nodeType == 'input') {
                    this.node.value = this.value;
            // 获取daa中的属性值
            get: function () {
                this.value = this.vm[this.name]; // 触发相应属性的get
        function Dep () {
            this.subs = []
        Dep.prototype = {
            addSub: function(sub) {
                this.subs.push(sub);
            notify: function() {
                this.subs.forEach(function(sub) {
                    sub.update();
        function Vue (options) {
            this.data = options.data;
            var data = this.data;
            observe(data, this);
            var id = options.el;
            var dom = nodeToFragment(document.getElementById(id), this);
            // 编译完成后,将dom返回到app中
            document.getElementById(id).appendChild(dom);
        var vm = new Vue({
            el: 'app',
            data: {
                text: 'hello world'
    </script>
</body>
</html>

我的理解

  • 架构意义角度(Web端的角度) MVC MVVM 在本质上都是为了 实现View和Model的解耦 MVC 是通过 Controller 实现了 View Model 解耦 ,一般用与客户端,或者 Web 端的整个架构过程;而 MVVM 是在 MVC 发展到 MVP 后(为了彻底解决View和Model的耦合问题),在提出 前后端分离 的基础上(考虑Coltroller的复用性,接口复用性),对 View层 进行了 增强(Vue.js) ,或者说细化了View层的表现手法,提出了通过 ViewModel 对视图层的 View Model 解耦。
    个人感觉 MVVM MVP 的整体 架构 是有 相似 的地方的,不同的是面对的 问题域 不同, MVP Web 架构整体的解决方案, MVVM 主要用于构建 基于事件驱动的 UI 平台(界面) ,适用于 前端 开发领域中 数据与界面相混合 的情况,所以它只专注于 视图层 抽象 视图 的状态和行为,实现了 用户界面的UI(View) 数据(Model) 解耦 。这个 View Model 虽然和 MVC 中描述的一样,但是不相同的,可以理解为 MVC View 中包含了 MVVM 的架构方式。
    一般 前后端分离 Web 开发中会结合 MVC MVVM 两种架构模式。使用 MVC 构建整体的 Web 架构,使用 MVVM 解决 View DOM data 的耦合问题。

在这里插入图片描述

  • 设计模式角度考虑 MVC 是基于 观察者 设计模式的, Model 作为一个主题, View 作为观察者,当一个 Model 变化时,会通知更新一个或多个依赖的 View ,反之;
    MVVM可以看做是基于 中介者 设计模式和 观察者 设计模式, View Model 通过 ViewModel 这个 中介者对象 进行交互,解耦了 View Mode l的同时实现 数据双向绑定
    同时 ViewModel 作为一个 主题对象 View Model 为两个观察者(或者可以理解为 View 为主题时, Model 为观察者,反之。这里的 Model View 起到一个 注册 通知 的作用,对于 观察者 模式的定义, ModelView 是主题的行为,但实际变化的是 View 或者 Model 个人觉得两种理解都没问题,理解不对的请小伙伴指出来 ),当 Model 变化时, ViewModel 数据绑定 通知并更新与之相关的多个 View ,反之,当 View 变化时, ViewModel DOM监听 通知更新相关的多个 Model

引用文献资料


  1. [浅析 web 前端 MVVM[db/ol]. https://zhuanlan.zhihu.com/p/54355504 ]( https://zhuanlan.zhihu.com/p/54355504)
  2. [百度百科[db/ol]. https://baike.baidu.com/item/MVVM/96310?fr=aladdin ]( https://baike.baidu.com/item/MVVM/96310?fr=aladdin)
  3. [上海科创数据资源中心[db/ol]. http://www.sstir.cn/search/list?keyword=MVVM ]( http://www.sstir.cn/search/list?keyword=MVVM)
  4. 程桂花.MVVM前后端数据交互中安全机制的研究与实现[D].浙江理工大学硕士学位设计,2017:6-7
  5. [你真的理解了MVC, MVP, MVVM吗?[db/ol]. https://blog.csdn.net/wdr2003/article/details/79811767 ]( https://blog.csdn.net/wdr2003/article/details/79811767)
  6. 易剑波.基于 MVVM 模式的 WEB 前端框架的研究[D].计算机工程应用技术,2016.19:76]
  7. [Vue MVVM理解及原理实现[db/ol]. https://juejin.cn/post/6844903929298288647 ]( https://juejin.cn/post/6844903929298288647)
在MVVM的框架下视图和模型是不能直接通信的。 它们通过ViewModel来通信,ViewModel通常要实现一个observer观察者,当数据发生变化,ViewModel能够监听到数据的这种变化 然后通知到对应的视图做自动更新,而当用户操作视图,ViewModel也能监听到视图的变化 然后通知数据做改动,这实际上就实现了数据的双向绑定。并且MVVM中的View 和 ViewModel可以互相通信。
Jetpack 系列(5)—— Android UI 架构演进:从 MVC 到 MVP、MVVM、MVI
Jetpack 系列(5)—— Android UI 架构演进:从 MVC 到 MVP、MVVM、MVI
【Android】MVC,MVP,MVVM的优缺点
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构.