一、概述
MVC模型是是一种软件设计的框架模式,它采用model-view-controller的方法把数据、视图、与业务逻辑分离,把众多的业务逻辑集合在一个部件里。简单的说,就是一种把数据模型,视图显示与人机交互三者分离开的一种编程方式。
- Model 模型: 封装的是数据源和所有基于对这些数据的业务逻辑。(直接参与管理应用程序的数据、逻辑和规则)
模型并不总是DataSet,DataTable之类的东西,它代表着一类组件(components)或类(class),这些组件或类可以向外部提供数据,同时也能从外部获取数据并将这些数据存储在某个地方,Model可提供组件的状态和操作状态的方法。简单的理解,可以把模型想象成“外观模式”。

- View视图: 封装的是对数据源Model的一种显示。
一个模型可以有多个视图,而一个视图理论上也可以同不同的模型关联起来。视图可以从模型中读取数据,但是不能修改或更新模型。
- Controller 控制器: 封装的是外界作用于模型的操作。
通常,这些操作会转发到模型上,并调用模型中相应的一个或者多个方法。(委托模型处理) 一Controller在Model和View之间起到了沟通的作用,处理用户在View上的输入,并转发给Model。这样Model和View两者之间可以做到松散耦合,甚至可以彼此不知道对方,而由Controller连接起这两个部分。控制器本身不输出任何东西和做任何处理。它只是接收请求并决定调用哪个模型去处理请求,然后再确定用哪个视图来显示返回的数据。
只要Controller改变了Model的数据或者属性,所有依赖的View都会自动更新。类似的,只要Controller改变了View,View会从潜在的Model中获取数据来刷新自己。
二、MVC模式用到的设计模式
在设计模式中,MVC实际上是一个比较高层的模式,它由多个更基本的设计模式组合而成,Model-View的关系实际上是Observer模式,模型的状态和试图的显示相互响应,而View-Controller则是由Strategy模式所描述的,View用一个特定的Controller的实例来实现一个特定的响应策略,更换不同的Controller,可以改变View对用户输入的响应。而其它的一些设计模式也很容易组合到这个体系中。比如,通过Composite模式,可以将多个View嵌套组合起来;通过FactoryMethod模式来指定View的Controller,等等。
三、MVC优点
1、分离数据和其表示,Model和View能够单独的开发,增加了程序了可维护性,可扩展性,并使测试变得更为容易
2、将控制逻辑和View分离,允许程序能够在运行时根据工作流、用户习惯或者模型状态来动态选择不同的用户界面。
四、MVC模式分类
3.1 主动 MVC 模式 (通常意义的MVC模式)
为什么说是主动的?因为View不是等Controller通知它Model更新了才从Model取数据并更新显示,而是自己监视Model的更新(如果用观察者模式)或主动询问Model是否更新。
视图将用户的行为告知控制器,控制器负责从视图中取得数据然后发送给模型。
注意:这里的控制器并没有执行视图的选择,因为模型和视图是关联的,及View上的用户请求通过Controller反馈到模型后,模型处理完请求对应的业务逻辑后,会将变化的数据主动通知到关联的视图。
3.2 被动 MVC 模式
与主动MVC的区别在于:
1、模型对视图和控制器一无所知,它仅仅是被它们使用
2、控制器使用视图,并通知它更新显示模型的数据
3、视图仅仅是在控制器通知它去模型取数据的时候它才这么做(视图并不会订阅或监视模型的更新)
4、控制器负责处理模型数据的变化
5、控制器可以包含对视图的渲染逻辑(视图选择)
3.3 其他结构图参考
以下两种图显示的MVC结构,也是合理的。

图1 被动模式和主动模式综合应用
图2 被动模式,只是将用户的输入”表现/作用”在控制层
二、模式示例
2.1 UML类图 对比中介者和观察者
2.2 源码示例
#pragma once#include <string>#include <memory>class StudentView;class StudentModel{public:std::string getName() { return name; }std::string getID() { return id; }void setStudentInfo(std::string name, std::string id){name = strName;id = ID;if (view)view->event();}void setView(std::shared_ptr<StudentView> viewPtr){view = viewPtr;}private:std::string name;std::string id;std::shared_ptr<StudentView> view = nullptr;};
#pragma once#include <iostream>#include <string>using namespace std;class StudentModel;class StudentView{public:void show(std::string name, std::string id){std::cout << "Student name: " << name << " ID: " << id << std::endl;}void event(){show(model->getName(), model->getID());}void setModel(std::shared_ptr<StudentView> modelPtr){model = modelPtr;}int menum(){std::cout << "=======view ui=======" << std::endl;std::cout << "=======请输入你的选择=======" << std::endl;int n ;std::cin >> n;return n;}private:std::shared_ptr<StudentModel> model = nullptr;};
#pragma once#include <iostream>#include <string>class Student;class StudentView;class StudentController{private:std::shared_ptr<StudentModel> model = nullptr;std::shared_ptr<StudentView> view = nullptr;public:void setModel(std::shared_ptr<StudentView> modelPtr){studentModel = modelPtr;}void setView(std::shared_ptr<StudentView> viewPtr){view = viewPtr;}void setStudentInfo(std::string name, std::string id){model->setStudentInfo(name, id);}void updateView(){view->show(studentModel->getName(), studentModel->getID());}void run(){int select = 0;do{select = view->menum();switch (select){case 0:break;case 1:setStudentInfo("王慧", "001");break;case 2:setStudentInfo("meetro", "001");break;case 3:updateView();break;default:printf("input error\n");break;}} while (select!=0);}};
#include "Student.h"#include "StudentView.h"#include "StudentController.h"void main(){auto model = std::make_shared<StudentModel>();auto view = std::make_shared<StudentView>();updateView->setView(view);studentModel->setModel(model);StudentController controller;controller->setView(view);controller->setModel(model);controller.run();return 0;}
Student:Name: RobertRoll No: 10Student:Name: JohnRoll No: 10
