一、概述
1.1 创建
1.1.1 架构
MVC架构最初是由计算机科学家Trygve Reenskaug在1979年提出的。他在研究Smalltalk-76编程语言的过程中,为了更好地组织和管理代码,提出了MVC架构的概念。Trygve Reenskaug在他的研究和实践中实现了MVC的基本原则和设计模式,并将其应用于图形用户界面(GUI)的开发。
因此,可以说MVC架构是由Trygve Reenskaug创建的。他的贡献和工作奠定了MVC作为一种流行的设计模式和架构思想的基础,对后续的软件开发产生了广泛的影响。虽然Trygve Reenskaug是MVC的创始人,但MVC的发展和应用是通过整个开发社区的努力和贡献来实现的。
1.1.2 框架
MVC框架并没有由单个个人或组织创建。它是由多个人共同贡献和发展而来的。最早的MVC概念是由计算机科学家Trygve Reenskaug在1979年提出的。他在Smalltalk-76编程语言的开发中引入了MVC的思想。
随着时间的推移,MVC的概念被引入到其他编程语言和平台中,并得到了不同开发者和研究者的贡献。许多编程语言和框架都实现了MVC模式,例如Ruby on Rails、ASP.NET MVC、Spring MVC等。这些框架在MVC的基础上添加了自己的特性和功能,以适应不同的应用需求。
因此,可以说MVC框架是通过整个开发社区的不断努力和贡献而创建和发展起来的。不同的人和组织在不同的时间和环境中对MVC进行了改进和实现,使其成为现代软件开发中广泛使用的架构模式之一。
1.2 发展
MVC架构自1979年被提出以来,经历了不断的发展和演化。以下是一些主要的MVC发展阶段:
1. 初始阶段:MVC最初是作为Smalltalk编程语言的一种设计模式提出的,用于构建图形用户界面(GUI)应用程序。它强调了关注点分离和模块化设计的重要性。
2. 后续发展:随着时间的推移,MVC被引入到其他编程语言和平台中。不同的开发社区和框架开始采用和演绎MVC的概念,并对其进行适应和扩展。
3. 变种和衍生架构:在MVC的基础上,还衍生出了一些变种和扩展的架构模式,如MVP(Model-View-Presenter)、MVVM(Model-View-ViewModel)和MVC5等。这些变种模式在一定程度上改变了MVC架构中组件之间的角色和交互方式,以适应不同的应用场景和开发需求。
4. 前端开发中的MV*模式:在前端开发中,基于JavaScript的开发框架、库和模式出现了各种各样的MV*(MVC、MVP、MVVM等)模式。这些模式以不同的方式实现了关注点分离,并提供了前端开发的组织和结构化方式。
5. 后端框架和Web开发:MVC架构被广泛应用于后端框架和Web开发中。许多流行的Web框架,如Ruby on Rails、ASP.NET MVC和Spring MVC等,都采用了MVC的设计原则和模式。
总的来说,MVC架构在不同的编程语言、平台和开发领域中得到了广泛的应用和发展。它引入了一种结构化和模块化的设计方法,使得软件开发更易于维护、扩展和团队协作。随着技术的进步和开发需求的变化,MVC架构也在不断演化和适应新的挑战和要求。
1.3 为什么有MVC
MVC架构的发展是为了解决软件开发中的一些问题和挑战。以下是一些发展MVC的原因:
1. 分离关注点:MVC架构通过将应用程序分为模型(Model)、视图(View)和控制器(Controller)三个组件,实现了关注点的分离。模型负责处理数据逻辑,视图负责展示用户界面,控制器负责处理用户输入和调度模型和视图之间的交互。这种分离允许开发人员更容易管理和维护代码,同时也支持代码的可重用性和可测试性。
2. 提高可维护性:MVC架构提供了清晰的组织结构,使得开发人员可以更方便地理解和修改代码。每个组件的责任明确,使得对于某个特定功能的修改更容易定位和实现。这样的结构有助于降低代码的耦合性和复杂性,提高软件的可维护性。
3. 支持多种用户界面:MVC架构使得视图和控制器之间的松耦合可以支持不同的用户界面。通过控制器处理用户输入和更新模型,视图可以根据模型的变化来更新用户界面。这意味着可以根据需要使用不同的视图来呈现相同的数据,并且可以更轻松地添加、修改或删除用户界面组件。
4. 支持团队协作:由于MVC架构清晰的分层和分工,不同的开发人员可以同时工作在不同的组件上,而不会相互干扰。开发人员可以独立地开发和测试每个组件,然后通过定义好的接口进行集成。这样的分工可以提高团队的协作效率,减少开发期间的冲突和问题。
总的来说,MVC架构通过关注点分离、可维护性、支持多种用户界面和团队协作等方面的优势,促使了它的发展并成为现代软件开发中广泛采用的架构模式之一。
二、架构和框架
2.1 架构的使用
MVC架构被广泛应用于软件开发中,特别是用于构建用户界面和Web应用程序。以下是一些MVC架构的常见使用情景:
1. Web开发:许多流行的Web框架和平台,如Ruby on Rails、ASP.NET MVC、Spring MVC等,都采用了MVC架构。在Web开发中,模型负责处理业务逻辑和数据持久化,视图负责呈现用户界面,控制器负责接收和处理用户请求,并决定哪个视图来展示给用户。
2. 桌面应用程序:MVC架构也可以用于构建桌面应用程序和图形用户界面(GUI)。在这种情况下,模型负责处理业务逻辑和数据操作,视图负责展示用户界面元素,控制器负责响应用户输入并更新模型和视图。
3. 移动应用程序:MVC架构可以应用于移动应用程序的开发。模型可以处理数据逻辑和存储,视图可以定义用户界面和布局,控制器可以处理用户输入和协调模型和视图之间的交互。
4. 游戏开发:在游戏开发中,MVC架构可以用于设计和管理游戏系统。模型可以表示游戏逻辑和状态,视图可以展示游戏界面和动画效果,控制器可以响应用户输入并控制游戏流程。
5. 嵌入式系统:MVC架构也可以应用于嵌入式系统开发中,例如物联网(IoT)设备或嵌入式软件。模型可以处理数据采集和处理,视图可以展示设备状态和信息,控制器可以根据输入指令控制设备操作。
总的来说,MVC架构可以应用于各种软件开发场景,通过关注点分离和组件化设计,帮助开发人员更容易管理和维护代码,提高可重用性和可测试性。它提供了一种结构化和模块化的设计方式,有助于构建灵活、可扩展和易于维护的应用程序。
2.2 架构的作用
MVC架构在软件开发中具有多种作用和优势,包括以下几点:
1. 关注点分离:MVC架构通过将应用程序划分为三个主要组件(模型、视图和控制器),实现了关注点的分离。模型负责处理业务逻辑和数据访问,视图负责呈现用户界面,控制器负责接收和处理用户输入。这种分离使得不同组件可以独立开发、测试和维护,提高了代码的可读性和可维护性。
2. 可重用性和扩展性:由于MVC架构的模块化设计,各个组件可以根据需要进行重用和扩展。例如,可以轻松地更换视图层或增加新的控制器,而不会对整个应用程序造成大规模改动。这种灵活性和可扩展性使得开发人员能够更快速地响应变化和需求。
3. 并行开发:MVC架构的分离性和清晰的角色划分使得多个开发人员可以并行工作。不同的开发人员可以专注于不同的组件,而不会相互干扰。这有助于提高开发团队的协作效率和项目的交付速度。
4. 用户界面和业务逻辑分离:MVC架构使得用户界面(视图)和业务逻辑(模型)可以分离开来。这样,改变界面布局或样式不会影响底层的业务逻辑。同时,业务逻辑的变化也不会影响用户界面的展示,实现了更好的可维护性和可扩展性。
5. 易于测试:由于MVC架构的分离性,各个组件可以独立进行单元测试。模型和控制器的测试可以针对业务逻辑进行,视图的测试可以验证界面的正确性。这种测试的分离性和独立性有助于提高测试覆盖率和测试质量。
综上所述,MVC架构在软件开发中扮演了重要的角色。它通过关注点分离、可重用性和扩展性、并行开发等方式,帮助开发人员设计和构建结构清晰、可维护、可测试的应用程序。这使得开发团队能够更高效地开发和维护软件,提供更好的用户体验和可靠性。
2.3 框架的使用
MVC框架的使用可以通过以下步骤来实现:
1. 选择合适的MVC框架:首先,你需要选择一个适合你项目需求和编程语言的MVC框架。一些流行的MVC框架包括Ruby on Rails、ASP.NET MVC、Spring MVC、Django等。根据你的技术栈和项目需求选择一个合适的框架。
2. 定义模型:根据你的业务需求,定义数据模型。模型代表了应用程序中的数据结构和业务逻辑。你可以使用框架提供的ORM(对象关系映射)工具或自己手动定义模型类。
3. 创建视图:设计和创建应用程序的用户界面。视图负责呈现模型中的数据,并与用户进行交互。视图可以是HTML页面、用户界面组件或其他形式的展示。
4. 实现控制器:创建控制器来处理用户请求和管理应用程序的逻辑。控制器接收用户的输入,调用适当的模型和逻辑进行处理,并最终选择合适的视图进行展示。控制器可以根据路由配置来确定哪个控制器方法处理特定的请求。
5. 设置路由:配置应用程序的路由规则,决定不同URL请求该由哪个控制器方法处理。路由定义了请求的URL模式与相应控制器方法之间的映射关系。
6. 数据交互:在模型、视图和控制器之间进行数据交互。模型从数据源中获取数据,视图通过模型获取数据并展示,控制器接收用户输入并更新模型和视图。
7. 测试和调试:进行单元测试和集成测试来确保应用程序的正常运行。对各个组件进行单元测试以验证其功能,进行集成测试以确保它们在整个系统中协同工作。
8. 部署和发布:将应用程序部署到适当的服务器或云平台,并进行发布。确保服务器环境配置正确,并配置域名和网络访问。
通过按照这些步骤,你可以使用MVC框架来组织和构建应用程序,以实现良好的代码结构和易于维护的开发模式。这将使你能够更高效地开发和扩展应用程序,并提供良好的用户体验。
2.4 框架的作用
MVC框架在软件开发中具有多种作用和优势,下面是一些主要的作用:
1. 分离关注点:MVC框架通过将应用程序分为模型(Model)、视图(View)和控制器(Controller)三个组件,实现了关注点的分离。模型负责业务逻辑和数据管理,视图负责用户界面展示,控制器负责接收和处理用户输入。这种分离可以使各个组件更加独立,易于理解、修改和维护。
2. 代码重用和可扩展性:MVC框架提供了一种层次结构和模块化的设计,使得代码可以更好地组织和重用。各个组件之间的解耦性使得可以独立地开发、测试和修改某个组件,而不会影响其他组件。这种模块化的设计也使得应用程序更容易扩展,可以增加新的模型、视图或控制器,而不需要修改已有的代码。
3. 增加可维护性:MVC框架的分层结构和关注点分离的特性使得代码更容易理解和维护。不同的组件职责清晰,代码逻辑更清晰明了,有助于团队合作和迭代开发。这种结构化的设计也使得调试和错误修复更加容易。
4. 支持并行开发:MVC框架的分离性和模块化的设计使得多个开发人员可以并行工作。不同的组件可以独立开发和测试,减少团队成员之间的代码冲突和依赖。这样可以提高开发效率,缩短项目开发周期。
5. 提供良好的用户体验:MVC框架使得视图层和用户界面的设计更加灵活和易于调整。视图可以根据不同设备和需求进行优化,提供良好的用户体验。控制器也可以处理用户输入,根据业务逻辑调整数据和界面的展示,提供个性化和交互式的用户体验。
总的来说,MVC框架在软件开发中起到了组织、规范和优化代码的作用。它通过关注点分离、代码重用和可扩展性等特性,帮助开发团队构建可维护、可扩展和良好用户体验的应用程序。
2.5 框架的制作流程
MVC框架的制作流程的简要概述:
1. 项目准备阶段:
- 了解项目需求和目标。
- 选择适合的编程语言和技术栈。
- 设计应用程序的功能和用户界面。
2. 模型设计阶段:
- 确定应用程序的业务逻辑和数据需求。
- 定义模型类和数据库结构。
- 实现数据模型的持久化和访问方法。
3. 视图设计阶段:
- 设计用户界面的布局和样式。
- 创建视图模板或组件。
- 配置视图与模型的交互和数据展示。
4. 控制器设计阶段:
- 创建处理用户输入的控制器。
- 设计路由规则和映射关系。
- 实现控制器方法来处理请求并调用相应的模型和视图。
5. 实现业务逻辑和交互:
- 在控制器方法中编写适当的业务逻辑。
- 通过模型处理数据的增删改查操作。
- 在视图中展示模型中的数据。
6. 测试和调试:
- 编写单元测试和集成测试来验证各个组件的功能。
- 识别和修复潜在的错误和问题。
- 进行用户界面的测试和调整。
7. 部署和发布:
- 将应用程序部署到适当的服务器或云平台。
- 配置运行环境和服务器设置。
- 进行发布和域名绑定。
这只是一个简要的流程概述,具体的制作流程可能会因项目规模、技术栈和团队流程而有所差异。建议在具体开发过程中结合项目需求和具体技术文档来进行实际操作和开发。
三、实例演示
3.1 实体类及模型驱动
3.1.1 实体
Book (书籍)类
package com.CloudJun.entity; /** * @author Cloud.Jun * @com.CloudJun.entity * @Book(说明):book(书籍类) */ public class Book { private int bid; private String bname; private float price; @Override public String toString() { return "Book [bid=" + bid + ", bname=" + bname + ", price=" + price + "]"; } public Book() { super(); } public Book(int bid, String bname, float price) { super(); this.bid = bid; this.bname = bname; this.price = price; } public int getBid() { return bid; } public void setBid(int bid) { this.bid = bid; } public String getBname() { return bname; } public void setBname(String bname) { this.bname = bname; } public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } }
3.1.2 模型驱动
ModelDriver 模型驱动接口
package com.CloudJun.framework; /** * @author Cloud.Jun * @com.CloudJun.framework * @ModelDriver(说明):模型驱动接口 */ public interface ModelDriver<T> { T getModel(); }
3.2 mvc.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <config> <!-- 1.往config标签中添加了一个action标签 --> <!-- 2.往action标签中添加了4个forward标签 --> <!-- 3.将action标签的属性值path、type发生了更改 --> <!-- 4.将forward标签的属性值name、path、redirect发生了更改 --> <!-- 以面向对象的思想思考上述操作 --> <!-- 1.configModel对象中添加一个actionModel对象,因为actionModel在configModel中是唯一的, --> <!-- 所以在configModel必然有一个属性(容器Map),能够以一对一的方式存储不同个actionModel,还有添加方法,查询方法 --> <!-- 2.actionModel 也有一个属性(容器Map),也有个添加的方法,查询方法 --> <!-- 3.actionModel 还有属性path、type --> <!-- 4.forwardModel 有属性name、path、redirect --> <action path="/order" type="com.CloudJun.entity.OrderAction"> <forward name="forward" path="/demo.jsp" redirect="false" /> <forward name="redirect" path="/demo.jsp" redirect="true" /> </action> <action path="/Book" type="com.CloudJun.entity.BookAction"> <forward name="forward" path="/demo.jsp" redirect="false" /> <forward name="redirect" path="/demo.jsp" redirect="true" /> </action> </config>
3.3 实体方法类
BookAction:书籍(Book)的方法类
package com.CloudJun.entity; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.CloudJun.framework.Action; import com.CloudJun.framework.ModelDriver; /** * @author Cloud.Jun * @com.CloudJun.entity * @BookAction(说明):BookAction是Book的所有方法类 */ public class BookAction extends Action implements ModelDriver<Book>{ private Book book = new Book(); /* * 1.要有表对应的类属性对象 Book book * 2.获取到所有的参数 及参数 req.getParameterMap(); * 3.将参数值封装到表对应的对象中 * 4.要做到所有子控制器通用 */ public String See(HttpServletRequest request, HttpServletResponse response) { //参数传递 request.setAttribute("String", "ikun的小黑子"); System.out.println("book(书籍)Action的查看(See)方法"); //返回值(是重定向还是转发)forward:转发,redirect:重定向 return "forward"; } public String Upda(HttpServletRequest request, HttpServletResponse response) { //参数传递 request.setAttribute("String", "ikun的小黑子"); System.out.println("book(书籍)Action的修改(Upda)方法"); //返回值(是重定向还是转发)forward:转发,redirect:重定向 return "redirect"; } public String Del(HttpServletRequest request, HttpServletResponse response) { request.setAttribute("String", "ikun的小黑子"); System.out.println("book(书籍)Action的删除(Del)方法"); //返回值(是重定向还是转发)forward:转发,redirect:重定向 return "redirect"; } public String Add(HttpServletRequest request, HttpServletResponse response) { request.setAttribute("String", "ikun的小黑子"); System.out.println("book(书籍)Action的增加(Add)方法"); //返回值(是重定向还是转发)forward:转发,redirect:重定向 return "redirect"; } @Override public Book getModel() { return book; } }
BookServlet获取参数并反射后调用相应方法
package com.CloudJun.Servlet; import java.io.IOException; import java.lang.reflect.Method; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author Cloud.Jun * @com.CloudJun.Servlet * @BookServlet(说明):书籍的Servlet反射的方法后调用 */ @WebServlet("/BookServlet.do") public class BookServlet extends HttpServlet { private static final long serialVersionUID = 1L; protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //根据JSP页面传递的值 String method = request.getParameter("method"); //通过反射类类方法的方法进行增删改查 try { Method m = this.getClass().getDeclaredMethod(method, HttpServletRequest.class,HttpServletResponse.class); m.setAccessible(true); m.invoke(this,request,response); } catch (Exception e) { e.printStackTrace(); } } private void See(HttpServletRequest request, HttpServletResponse response) { System.out.println("book(书籍)Servlet的查看(See)方法"); } private void Upda(HttpServletRequest request, HttpServletResponse response) { System.out.println("book(书籍)Servlet的修改(Upda)方法"); } private void Del(HttpServletRequest request, HttpServletResponse response) { System.out.println("book(书籍)Servlet的删除(Del)方法"); } private void Add(HttpServletRequest request, HttpServletResponse response) { System.out.println("book(书籍)Servlet的增加(Add)方法"); } }
3.4 控制器及子控制器
3.4.1 ControllerServlet
控制器 ControllerServlet
package com.CloudJun.framework; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanUtils; import com.CloudJun.framework.model.ActionModel; import com.CloudJun.framework.model.ConfigModel; import com.CloudJun.framework.model.ConfigModelFactory; import com.CloudJun.framework.model.ForwardModel; @WebServlet("*.do") public class ControllerServlet extends HttpServlet { private static final long serialVersionUID = 1L; // Map<String, Action> actionMap = new HashMap<String, Action>(); // 以前所有的子控制器是放到map集合中,现在所有的子控制器在mvc.xml中,其实就是放到configModel对象中 private ConfigModel configModel; @Override public void init() throws ServletException { // actionMap.put("/Book", new BookAction()); try { // configModel包含了所有的子控制器 configModel = ConfigModelFactory.build(); } catch (Exception e) { e.printStackTrace(); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String uri = request.getRequestURI(); uri = uri.substring(uri.lastIndexOf("/"), uri.lastIndexOf(".")); // Action action = actionMap.get(uri); // 要通过uri找到/book,在configModel对象中找 ActionModel actionModel = configModel.pop(uri); // 判断如果为空在页面给与异常提示 if (actionModel == null) throw new RuntimeException("action not config"); // 获取类路径 String type = actionModel.getType(); Action action = null; try { action = (Action) Class.forName(type).newInstance(); // bookAction有没有实现ModelDriver接口 if (action instanceof ModelDriver) { ModelDriver md = (ModelDriver) action; Object bean = md.getModel(); BeanUtils.populate(bean, request.getParameterMap()); } //具体业务代码执行后的返回值 forward:转发,redirect:重定向 String execut = action.execut(request, response); //要通过返回值拿到,该方法结果是重定向还是转发,还是跳转哪个页面 ForwardModel forwardModel = actionModel.pop(execut); if(forwardModel != null) { //获取返回值true后false boolean redirect = forwardModel.isRedirect(); String path = forwardModel.getPath(); if(redirect) { //getContextPath()加载时防止页面丢失 response.sendRedirect(request.getContextPath() + "/" + path); }else { request.getRequestDispatcher(path).forward(request, response); } } } catch (Exception e) { e.printStackTrace(); } } }
3.4.2 Action
Action 子控制器:处理请求
package com.CloudJun.framework; import java.lang.reflect.Method; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author Cloud.Jun * @com.CloudJun.framework * @Action(说明):处理浏览器发过来的请求类 */ public class Action { public String execut(HttpServletRequest request, HttpServletResponse response) throws Exception { //根据JSP页面传递的值 String method = request.getParameter("method"); //定义返回值确定是重定向还是转发 String res = ""; //通过反射类类方法的方法进行增删改查 try { Method m = this.getClass().getDeclaredMethod(method, HttpServletRequest.class,HttpServletResponse.class); m.setAccessible(true); res = (String) m.invoke(this,request,response); } catch (Exception e) { e.printStackTrace(); } return res; } }
3.5 页面测试
代码如下:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <h3>书籍的方法功能--优化为配置文件及获取参数和跳转方法</h3><hr> <a href="Book.do?method=Add&bid=1&bname=ikun&price=999">增加</a> <a href="Book.do?method=Del&bid=1">删除</a> <a href="Book.do?method=Upda&bid=1&bname=小黑子&price=666">修改</a> <a href="Book.do?method=See&bid=1">查询</a> </body> </html>
结果:
页面显示:
增 删 改的测试的是重定向不会带参数:
查询是参数转发所以带参数:
带来的收获
MVC框架给我们带来了许多收获,下面是一些主要的收获:
1. 结构清晰和可维护性:MVC框架通过将应用程序划分为模型、视图和控制器的组件,提供了一种清晰的结构和分层设计。这种结构使得代码更易于理解、修改和维护。各个组件之间的关注点分离,使得开发人员能够更专注于某个特定的组件,提高代码的可读性和可维护性。
2. 代码重用和可扩展性:MVC框架提供了模块化的设计和组件的解耦,使得代码可以更好地重用和扩展。通过划分业务逻辑、数据模型和用户界面的职责,可以独立地开发、测试和修改这些组件,而不需要对整个应用程序进行大规模的修改。这种可扩展性和重用性使得开发人员能够更高效地构建和扩展应用程序。
3. 并行开发和团队协作:MVC框架的分层结构和关注点分离的特性使得多个开发人员可以并行工作,并且各个组件之间可以独立开发和测试。这种并行开发和团队协作的模式可以提高开发效率和项目交付速度。开发人员可以根据各自的专长和职责来负责特定的组件,减少代码冲突和依赖,提高团队合作的效果。
4. 易于测试和调试:MVC框架的分层结构使得各个组件可以独立进行单元测试和集成测试。模型、视图和控制器的职责清晰,可以分别对它们进行测试,提高测试的覆盖率和质量。同时,通过关注点分离和模块化的设计,也使得调试和错误修复更加容易,能够更快地定位问题和进行修复。
5. 用户体验和界面优化:MVC框架使得视图层和用户界面的设计更加灵活和易于优化。视图可以根据不同设备和需求进行定制和优化,提供良好的用户体验。控制器也可以根据业务逻辑来调整数据和界面的展示,实现个性化和交互式的用户体验。
综上所述,MVC框架给我们带来了结构清晰、可维护性强的代码架构,促进了代码重用和可扩展性,提供了并行开发和团队协作的机制,方便了测试和调试,同时也提供了更好的用户体验和界面优化的能力。这些收获使得我们能够更高效地开发和维护应用程序,提供更好的用户体验和可靠性。