一、概述

MVC模型是是一种软件设计的框架模式,它采用model-view-controller的方法把数据、视图、与业务逻辑分离,把众多的业务逻辑集合在一个部件里。简单的说,就是一种把数据模型,视图显示与人机交互三者分离开的一种编程方式。

  • Model 模型: 封装的是数据源和所有基于对这些数据的业务逻辑。(直接参与管理应用程序的数据、逻辑和规则)

模型并不总是DataSet,DataTable之类的东西,它代表着一类组件(components)或类(class),这些组件或类可以向外部提供数据,同时也能从外部获取数据并将这些数据存储在某个地方,Model可提供组件的状态和操作状态的方法。简单的理解,可以把模型想象成“外观模式”。
dabf0f54d6a86b9f58b82f72c97f4896_ce85668f55e41ce7513d92c9.jpg

  • 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反馈到模型后,模型处理完请求对应的业务逻辑后,会将变化的数据主动通知到关联的视图。
MVC模式 - 图2

3.2 被动 MVC 模式

与主动MVC的区别在于:
1、模型对视图和控制器一无所知,它仅仅是被它们使用
2、控制器使用视图,并通知它更新显示模型的数据
3、视图仅仅是在控制器通知它去模型取数据的时候它才这么做(视图并不会订阅或监视模型的更新)
4、控制器负责处理模型数据的变化
5、控制器可以包含对视图的渲染逻辑(视图选择)
MVC模式 - 图3

3.3 其他结构图参考

以下两种图显示的MVC结构,也是合理的。

image.png
图1 被动模式和主动模式综合应用
MVC模式 - 图5
图2 被动模式,只是将用户的输入”表现/作用”在控制层

二、模式示例

2.1 UML类图 对比中介者和观察者

2.2 源码示例

  1. #pragma once
  2. #include <string>
  3. #include <memory>
  4. class StudentView;
  5. class StudentModel
  6. {
  7. public:
  8. std::string getName() { return name; }
  9. std::string getID() { return id; }
  10. void setStudentInfo(std::string name, std::string id)
  11. {
  12. name = strName;
  13. id = ID;
  14. if (view)
  15. view->event();
  16. }
  17. void setView(std::shared_ptr<StudentView> viewPtr)
  18. {
  19. view = viewPtr;
  20. }
  21. private:
  22. std::string name;
  23. std::string id;
  24. std::shared_ptr<StudentView> view = nullptr;
  25. };
  1. #pragma once
  2. #include <iostream>
  3. #include <string>
  4. using namespace std;
  5. class StudentModel;
  6. class StudentView
  7. {
  8. public:
  9. void show(std::string name, std::string id)
  10. {
  11. std::cout << "Student name: " << name << " ID: " << id << std::endl;
  12. }
  13. void event()
  14. {
  15. show(model->getName(), model->getID());
  16. }
  17. void setModel(std::shared_ptr<StudentView> modelPtr)
  18. {
  19. model = modelPtr;
  20. }
  21. int menum()
  22. {
  23. std::cout << "=======view ui=======" << std::endl;
  24. std::cout << "=======请输入你的选择=======" << std::endl;
  25. int n ;
  26. std::cin >> n;
  27. return n;
  28. }
  29. private:
  30. std::shared_ptr<StudentModel> model = nullptr;
  31. };
  1. #pragma once
  2. #include <iostream>
  3. #include <string>
  4. class Student;
  5. class StudentView;
  6. class StudentController
  7. {
  8. private:
  9. std::shared_ptr<StudentModel> model = nullptr;
  10. std::shared_ptr<StudentView> view = nullptr;
  11. public:
  12. void setModel(std::shared_ptr<StudentView> modelPtr)
  13. {
  14. studentModel = modelPtr;
  15. }
  16. void setView(std::shared_ptr<StudentView> viewPtr)
  17. {
  18. view = viewPtr;
  19. }
  20. void setStudentInfo(std::string name, std::string id)
  21. {
  22. model->setStudentInfo(name, id);
  23. }
  24. void updateView()
  25. {
  26. view->show(studentModel->getName(), studentModel->getID());
  27. }
  28. void run()
  29. {
  30. int select = 0;
  31. do
  32. {
  33. select = view->menum();
  34. switch (select)
  35. {
  36. case 0:
  37. break;
  38. case 1:
  39. setStudentInfo("王慧", "001");
  40. break;
  41. case 2:
  42. setStudentInfo("meetro", "001");
  43. break;
  44. case 3:
  45. updateView();
  46. break;
  47. default:printf("input error\n");
  48. break;
  49. }
  50. } while (select!=0);
  51. }
  52. };
  1. #include "Student.h"
  2. #include "StudentView.h"
  3. #include "StudentController.h"
  4. void main()
  5. {
  6. auto model = std::make_shared<StudentModel>();
  7. auto view = std::make_shared<StudentView>();
  8. updateView->setView(view);
  9. studentModel->setModel(model);
  10. StudentController controller;
  11. controller->setView(view);
  12. controller->setModel(model);
  13. controller.run();
  14. return 0;
  15. }
  1. Student:
  2. Name: Robert
  3. Roll No: 10
  4. Student:
  5. Name: John
  6. Roll No: 10