MVC模式浅谈

article/2025/9/12 21:48:05

一、MVC模式概述

模型-视图-控制器(MVC模式)是一种非常经典的软件架构模式,在UI框架和UI设计思路中扮演着非常重要的角色。从设计模式的角度来看,MVC模式是一种复合模式,它将多个设计模式在一种解决方案中结合起来,用来解决许多设计问题。MVC模式把用户界面交互分拆到不同的三种角色中,使应用程序被分成三个核心部件:Model(模型)、View(视图)、Control(控制器)。它们各自处理自己的任务:

(1)模型:模型持有所有的数据、状态和程序逻辑。模型独立于视图和控制器。

(2)视图:用来呈现模型。视图通常直接从模型中取得它需要显示的状态与数据。对于相同的信息可以有多个不同的显示形式或视图。

(3)控制器:位于视图和模型中间,负责接受用户的输入,将输入进行解析并反馈给模型,通常一个视图具有一个控制器。

MVC模式将它们分离以提高系统的灵活性和复用性,不使用MVC模式,用户界面设计往往将这些对象混在一起。MVC模式实现了模型和视图的分离,这带来了几个好处。

(1)一个模型提供不同的多个视图表现形式,也能够为一个模型创建新的视图而无须重写模型。一旦模型的数据发生变化,模型将通知有关的视图,每个视图相应地刷新自己。

(2)模型可复用。因为模型是独立于视图的,所以可以把一个模型独立地移植到新的平台工作。

(3)提高开发效率。在开发界面显示部分时,你仅仅需要考虑的是如何布局一个好的用户界面;开发模型时,你仅仅要考虑的是业务逻辑和数据维护,这样能使开发者专注于某一方面的开发,提高开发效率。


图1.1MVC模式结构图

如图1.1所示,视图中用户的输入被控制器解析后,控制器改变状态激活模型,模型根据业务逻辑维护数据,并通知视图数据发生变化,视图得到通知后从模型中获取数据刷新自己。

 

二、深入解析MVC模式

对MVC模式有了一个初步的认识之后,我们可以继续深入地了解它。MVC模式的关键是实现了视图和模型的分离。这是如何实现的呢?MVC模式通过建立一个“发布/订阅”(publish-subscribe)的机制来分离视图和模型。发布-订阅(publish-subscribe)机制的目标是发布者,它发出通知时并不需知道谁是它的观察者。可以有任意数目的观察者订阅并接收通知。MVC模式最重要的是用到了Observer(观察者模式),正是观察者模式实现了发布-订阅(publish-subscribe)机制,实现了视图和模型的分离。因此谈到MVC模式就必须谈到观察者模式。如图2.1所示。


图2.1 观察者模式

观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

图2.1中Subject我们称为主题,Observer称为观察者。主题提供注册观察者、移除观察者和通知观察者的接口,这样只要观察者注册成为主题的一个观察者的话,主题在状态发生变化时会通知观察者。观察者有一个更新自己的接口,当收到主题的通知之后观察者就会调用该接口更新自己。如何实现注册和通知的呢?如果是用C++或java的话,主题就需要有一个观察者链表,注册就是将观察者加入到该链表中,移除则是从该链表中删除,当主题状态变化时就遍历该链表所有的观察者通知它们更新自己。在c#中可以通过委托实现注册。

      观察者模式中的主题就对应于MVC模式中Model(模型),观察者就对应于MVC模式中的View(视图)。视图向模型注册成为观察者,模型(主题)变化时就通知视图(观察者)更新自己,但是还有一个问题,我们如果不引入控制器的话,直接将接受用户输入并解析输入操纵模型的功能放到视图中的话会产生两个问题:第一、会造成视图代码变得复杂,使得视图就有了两个责任,不但要管理用户界面,还要处理如何控制模型的逻辑,有违单一责任的设计原则,一个类应该仅有一个引起它变化的原因,如果一个类承担的责任过多,就等于把这些责任耦合在一起,一个责任的变化可能会削弱或抑制这个类完成其他责任的能力,这种耦合会导致脆弱的设计,当变化同时面临两个或多个方向变化时设计会遭到意想不到的破坏甚至根本没办法处理。第二、会造成模型和视图的紧耦合,如果你想复用此视图来处理其他模型,根本不可能。于是把控制器从视图中分离出来,将视图和模型解耦,通过控制器来保持控制器和视图之间的松耦合,使设计更有弹性和容易扩展,足以容纳以后的改变。

控制器相当于是视图的行为,我们还要考虑到今后可能面临的变化,例如视图想换一种行为,我们是否做好了应付这种变化的准备呢?我们不应该将视图和控制器紧耦合,例如不要一开始就将视图和某一个具体行为绑定起来,这样会使视图更换行为的时候变得很困难,我们应该能动态的给视图指定一个行为,用多态使视图和控制器之间松耦合,可以使视图轻松地更换行为,于是策略模式登场了,策略模式正是用来解决这个问题的。如图2.2所示。   

      策略模式:定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。

      MVC模式视图和控制器实现了经典的策略模式:视图是一个对象,可以被调整使用不同的策略(行为),而控制器提供了策略(行为)。视图想换另一种行为,换控制器就可以了。视图只关心系统中可视的部分,对于任何界面行为,都委托给控制器处理。使用策略模式也可以让视图和模型之间的关系解耦,因为控制器负责和模型交互来传递用户的请求。对于工作是怎么完成的,视图毫不知情。


                                                                           图2.2策略模式

三、MVC模式的应用

      GOF四人组提出MVC模式的主要关系是由Observer(观察者模式)、Composite(组合模式)和Strategy(策略模式)三个设计模式给出的。当然其中还可能使用了其他的设计模式,这要根据具体场景的需要来决定。GOF四人组提出复杂的视图可以根据实际需要用组合模式来实现,当然,也要注意避免过度设计,如果视图的结构不复杂就没必要采用组合模式了。我们和一个同事一起开发的项目中,UI框架的设计我采用了MVC模式,主要结合了Observer(观察者模式)、Strategy(策略模式)、Command(命令模式)和Singleton(单件模式)。用户界面不太复杂,因此视图不需要应用组合模式,在界面的框架设计中,界面菜单、对话框、树形控件和表格控件对应于MVC模式中的View(视图),其中对话框采用了单件模式,保证一个类仅有一个对话框实例,并提供一个访问它的全局访问点。控制器位于视图和命令对象或模型中间,将界面请求封装成一个命令对象,命令对象执行控制器发送过来的命令,根据命令对象模型负责处理逻辑和数据。项目UI框架中采用Observer(观察者模式)和Strategy(策略模式)使视图和模型分离,并让视图能灵活地更换行为,在前面已有详述,不再赘述,我要重点提的是我为什么要采用Command(命令模式)以及如何将命令模式嵌入到MVC模式当中。如图3.1所示。


图3.1 命令模式

命令模式:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。

根据项目的需求:用户可以通过工具条按钮、菜单按钮、对话框按钮或鼠标右键等操作来执行同一项请求;支持取消和重做操作;很容易增加或更换新的命令请求。这些问题都可以通过命令模式来解决。命令模式可以使不同地方的按钮或操作代表同一项功能,只需要让它们共享响应具体Command子类的同一实例即可。还可以通过多态动态替换Command对象从而轻松地更换请求命令。Command的Execute操作可在实施操作前将状态存储起来,在取消操作时这个状态用来消除该操作的影响。Command具体对象调用一个Unexecute操作,该操作取消上一次Execute调用的效果。执行的命令被存储在一个历史列表中。可通过向后和向前遍历这一列表并分别调用Unexecute和Execute来实现次数不限的“取消”和“重做”。Command模式将调用操作的对象与知道如何实现该操作的对象解耦。Command可像其他的对象一样被方便的替换和扩展。在菜单中增加新的调用命令时只要增加新的Command,而无需改变已有的类。我们将Command对象放到控制器中,控制器接收视图的输入并解析,将用户输入发送给Command对象,Command对象调用执行接口,然后在Command子类中将用户输入发给模型,模型执行逻辑维护数据,并通知视图。视图得到通知后获取模型的新数据并更新自己。项目的界面框架采用这种MVC模式使得软件变得灵活、易于扩展和维护。

 

四、结论

在软件开发的过程中,开发人员最为担心的是需求的不断变化,而这些变化又不是开发人员所能控制的,因此,为了适应这些变化,就要使用设计模式。MVC模式在一个解决方案中综合运用多种设计模式,是模式中的模式,按MVC模式的设计,一个模型可以表现为多个视图,这样可以减少代码的冗余。模型返回的数据不带任何显示格式,因此这些模型也可直接应用于接口的使用。由于一个应用程序被分离为三层,因此有时改变其中的一层就能满足应用的改变。一个应用的业务流程或者业务规则的改变只需改动MVC的模型层,而不会影响到视图和控制器。不过,使用设计模式并不是一定就能得到一个好的设计,过分地使用设计模式会增加程序的复杂性和晦涩性,让程序不易理解,从而降低了程序的易维护性。因此要避免过度使用设计模式,我们应根据面向对象的设计原则和实际情况综合考虑我们的设计,从而设计出具有良好扩展性和易维护性的软件。


原文地址:http://blog.sina.com.cn/s/blog_563cc1be0100emym.html


http://chatgpt.dhexx.cn/article/Yu646qHf.shtml

相关文章

​MVC​​模式简介

MVC模式简介 MVC简介 MVC的全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,是一种软件设计典范。它是用一种业务逻辑、数据与界面显示分离的方法来组织代码,将众多的业务逻辑聚集到…

MVC模式介绍

本文主要介绍 MVC 模式的相关知识。 1 What MVC(Model–View–Controller)模式是软件工程中的一种软件架构模式,它把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器&a…

【js】addEventListener() 用法

addEventListener() 方法用于向指定元素添加事件句柄。 addEventListener() 方法添加的事件句柄不会覆盖已存在的事件句柄。 你可以向一个元素添加多个事件句柄。 你可以向同个元素添加多个同类型的事件句柄,如:两个 "click" 事件。 你可以…

JS中addEventListener的用法

事件模型 这是一个完整的事件流: 事件捕获----处于目标----事件冒泡 注意:事件捕获由于浏览器兼容问题用的比较少 事件处理程序(addEventListener) 格式为:element.addEventListener(type, handle, false); type: 事…

JS addEventListener()方法

addEventListener(),事件监听,用于向指定的元素添加事件监听 语法:addEventListener(event,function,useCapture); 第一个参数event:指事件的类型(如’click’,‘mousedown’) 第二个参数function&#xf…

JS中addEventListener的使用

使用addEventListener绑定事件:MDN中addEventListener()说明 使用removeEventListener可以解绑事件: MDN中removeEventListener()说明 1,我们使用addEventListener的时候,主要用来实现事件的绑定监听的 存在三个参数 target.addE…

addEventListener()使用方法

document.addEventListener() 方法用于向文档添加事件句柄&#xff0c;即事件监听。先看下面代码&#xff0c;稍后进行讲解。 <!DOCTYPE html> <html> <head><meta charset"utf-8"><title></title> </head> <body>&…

关于JS中addEventListener的使用

关于JS中addEventListener的使用 MDN中addEventListener()说明 使用removeEventListener可以解绑事件 MDN中removeEventListener()说明 主要用来实现事件的绑定 存在三个参数 target.addEventListener(type, listener, useCapture); type: 表示监听事件类型的字符串。类似于…

JavaScript属性及正则表达式

目录 offset、client、scroll属性offsetclientscroll 正则表达式什么是正则表达式正则表达式的特点正则表达式的创建正则表达式的检验正则表达式的修饰符模式修饰符边界符预定义符转义特殊字符字符类字符组合取反符量词符括号字符 正则表达式的优先级String类中的方法match方法…

前端js正则表达式

正则表达式 第一章 正则表达式字符匹配攻略 1.1. 两种模糊匹配 1.1.1. 横向模糊匹配 一个正则可匹配的字符串的长度不是固定的&#xff0c;可以是多种情况的。譬如 {m,n}&#xff0c;表示连续出现最少 m 次&#xff0c;最多 n 次。其实现的方式是使用量词。例如let reg /a…

JS正则表达式字符匹配

正则表达式字符匹配 这是阅读《JavaScript正则表达式迷你书》后整理的一些笔记。 正则表达式是匹配模式&#xff0c;要么匹配字符&#xff0c;要么匹配位置。 下面主要介绍匹配字符的情况&#xff0c;匹配位置的情况我也正在学习中。 两种模糊匹配&#xff1a; 1.横向模糊匹…

JS正则表达式

JS正则表达式 0.前言 首先是一些资料[在线测试网站](regex101: build, test, and debug regex)和简明易懂教程。 正则表达式是一组由字母和符号组成的特殊文本&#xff0c;它可以用来从文本中找出满足你想要的格式的句子。 一个正则表达式是一种从左到右匹配主体字符串的模式。…

Spring框架总结

简介 创立于 2003年 , 是为了解决企业级开发的复杂性的! 是一个分层的se/ee(javase和java ee)一站式轻量级开源框架 作用&#xff1a; 1.Spring是一个开元的轻量级的应用开发框架&#xff0c;其目的是用于简化企业级应用程序开发&#xff0c;减少侵入&#xff1b; 2.Spring的…

Spring框架特点

Spring是什么&#xff1f; spring是一个轻量级的 IOC&#xff08;控制反转&#xff09;和AOP(面向切面)的编程。 什么是IOC? IOC(控制反转) &#xff1a;传统JAVA SE 程序设计&#xff0c;我们直接在程序内部通过new来创建对象&#xff0c;是程序主动去创建依赖对象&#x…

Spring框架常用注解

Spring常用注解 Controller Controller 用来响应页面&#xff0c;表示当前的类为控制器。 在SpringMVC 中&#xff0c;控制器Controller 负责处理由DispatcherServlet 分发的请求&#xff0c;它把用户请求的数据经过业务处理层处理之后封装成一个Model &#xff0c;然后再把该…

浅谈我对spring框架的理解

总所周知&#xff0c;java界乃由五大传统框架&#xff1a;1.核心业务层框架&#xff08;地位不可动摇&#xff09;spring,2.控制层框架&#xff1a;spring MVC与struts2, 持久层框架&#xff1a;Mybatis&#xff0c;hibernate。 先从spring说起吧&#xff0c;了解过spring的同学…

Spring框架(一):spring框架的简介

一、spring框架的概念 Spring是一个开源轻量级的控制反转(IoC)和面向切面(AOP)的容器框架&#xff0c;它由Rod Johnson创建。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而&#xff0c;Spring的用途不仅限于服务…

关于对Spring框架的详解

Spring框架 基本概念Spring的形成主要模块三层架构Spring的优点对于Spring 框架中都用到设计模式&#xff1a; 基本概念 Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而&#xff0c;Spring的用途不仅仅限于服务…

【Spring框架】Spring框架介绍

文章目录 Spring框架介绍Spring两大核心技术 Spring的优点Spring体系介绍核心容器数据访问/集成Web页面其他模块 Spring框架介绍 Spring框架是分层的 Java SE/EE 应用 full-stack 全栈式轻量级开源框架&#xff0c;以 IOC(Inverse Of Control&#xff1a;控制反转)和 AOP(Aspe…

【Java】Spring框架

一、Spring简介 简介 Spring是分层的Java SE/EE应用full-stack轻量级开源框架&#xff0c;以IoC&#xff08;Inverse Of Control&#xff1a;反转控制&#xff09;和AOP&#xff08;Aspect Oriented Programming&#xff1a;面向切面编程&#xff09;为内核。提供了展现层Spr…