当前位置: 首页 > news >正文

MVC设计模式

在当今的软件开发领域,MVC(Model-View-Controller)设计模式已经成为了一种广泛使用的架构模式。它为应用程序提供了一种结构化的方法,将数据、用户界面和业务逻辑分开,从而使得应用程序更易于维护、扩展和重用。

一、MVC的概述
MVC是一种分层的设计,主要用于解决UI交互方面的经验体系。它包括Model、View和Controller三部分,分别负责数据的存储、视图界面的显示和业务逻辑的处理。MVC模式有助于降低代码的耦合度,实现界面、数据和逻辑的分离,从而易于代码的维护和拓展。

二、MVC的组成部分
模型(Model):模型是应用程序的数据和业务逻辑的核心。它负责处理与数据相关的所有操作,例如数据的增删改查、验证和持久化等。模型是与数据源直接交互的部分,不涉及用户界面或用户输入的处理。
视图(View):视图是应用程序的用户界面。它负责显示数据给用户,并接收用户的输入。视图只关注如何展示数据,而不关心数据从哪里来或应该如何处理。
控制器(Controller):控制器是模型和视图之间的中介。它负责接收用户的输入,处理这些输入,并更新模型和视图。控制器的主要任务是处理用户交互,并根据用户的操作更新数据和界面。控制器不包含任何与数据或用户界面相关的代码,而是专注于处理用户交互和协调模型和视图之间的通信。

三、MVC的优势
MVC模式的优点主要表现在以下几个方面:

解耦:MVC模式将应用程序的不同部分(数据、用户界面和业务逻辑)分离,降低了它们之间的耦合度。这使得开发人员可以独立地专注于各自的部分,提高了开发效率和代码的可维护性。
代码组织:MVC模式为应用程序提供了一种清晰的代码组织结构,使得代码更加模块化和易于管理。这种结构也有助于团队之间的协作,使得不同的开发人员可以专注于不同的部分。
可扩展性:由于MVC模式将应用程序的不同部分分离,因此当应用程序需要扩展时,可以更容易地添加新的功能或模块,而不会对现有的代码造成太大的影响。
可重用性:MVC模式使得模型、视图和控制器的分离,这使得它们可以独立地重用。例如,同一个模型可以与不同的视图或控制器一起使用,或者同一个视图可以用在不同的应用程序中。
易于测试和维护:由于MVC模式将应用程序的不同部分分离,因此可以更容易地对每个部分进行单元测试和集成测试。此外,由于代码的模块化结构,使得代码更易于维护和修改。

四、Unity游戏开发中的MVC
这里提供一个MVC模式的基本功能框架。

Model

using System.Collections;
using System.Collections.Generic;
using UnityEngine;//Model基类
public class BaseModel
{public BaseController controller;//有参构造public BaseModel(BaseController control){this.controller = control;}//无参构造public BaseModel(){}//初始化public virtual void Init(){}
}

View

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;//面板基类,因为需要挂载到场景对象上需要继承MonoBehaviour
public class BaseView : MonoBehaviour
{//面板ID属性public int ViewId { get; set; }//面板控制器public BaseController Controller { get; set; }//面板cavansprotected Canvas _canvas;protected Dictionary<string,GameObject> _ObjCache = new Dictionary<string, GameObject>();//面板中对象缓存private bool _isInit = false; //是否初始化void Awake(){_canvas = gameObject.GetComponent<Canvas>();OnAwake();}void Start(){OnStart();}protected virtual void OnAwake(){}protected virtual void OnStart(){}//调用指定控制器的注册方法public void ApplyControllerFunc(int controllerKey, string eventName, params object[] args){this.Controller.ApplyControllerFunc(controllerKey,eventName,args);}//调用自己控制器的注册方法public void ApplyFunc(string eventName, params object[] args){this.Controller.ApplyFunc(eventName,args);}//关闭界面public virtual void Close(params object[] args){SetVisible(false);}//销毁界面public void DestroyView(){Controller = null;Destroy(gameObject);}//初始化数据public virtual void InitData(){_isInit = true;}//初始化UIpublic virtual void InitUI(){}public bool IsInit(){return _isInit;}public bool IsShow(){return _canvas.enabled == true;}public virtual void Open(params object[] args){}public void SetVisible(bool value){this._canvas.enabled = value;}//查找面板中的对象public GameObject Find(string name){if(_ObjCache.ContainsKey(name)){return _ObjCache[name];}_ObjCache.Add(name,transform.Find(name).gameObject);return _ObjCache[name];}public T Find<T>(string name) where T:Component{GameObject obj = Find(name);return obj.GetComponent<T>();}
}

Controller

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;//控制器基类
public class BaseController
{private Dictionary<string,Action<object[]>> message;//事件列表protected BaseModel model;//模版数据public BaseController(){message = new Dictionary<string, Action<object[]>>();}//注册后,调用的初始化函数(要求所有控制器初始化后执行)public virtual void Init(){}public virtual void OnLoadView(IBaseView view){}//加载视图//打开视图public virtual void OpenView(IBaseView view){}//关闭视图public virtual void CloseView(IBaseView view){}//注册模版事件public void RegisterFunc(string eventName,Action<object[]> callback){if(message.ContainsKey(eventName)){message[eventName]+=callback;}else{message.Add(eventName,callback);}}//移除模版事件public void UnRegisterFunc(string eventName){if(message.ContainsKey(eventName)){message.Remove(eventName);}}//触发本模块事件public void ApplyFunc(string eventName, params object[] args){if(message.ContainsKey(eventName)){message[eventName].Invoke(args);}else{Debug.Log("error:"+eventName);}}//触发其他模板的事件public void ApplyControllerFunc(int controllerKey,string eventName, params object[] args){GameApp.ControllerManager.ApplyFunc(controllerKey,eventName,args);}//public void ApplyControllerFunc(ControllerType controllerType,string eventName,params object[] args){ApplyControllerFunc((int)controllerType,eventName,args);}//设置模型数据public void SetModel(BaseModel model){this.model = model;this.model.controller = this;}//得到模型数据public BaseModel GetModel(){return model;}//得到模型数据泛型public T GetModel<T>() where T:BaseModel{return model as T;}//得到指定控制器控制的模型public BaseModel GetControllerMode(int controllerKey){return GameApp.ControllerManager.GetControllerModel(controllerKey);}//删除控制器public virtual void Destroy(){RemoveModuleEvent();RemoveGlobalEvent();}//初始化模板事件public virtual void InitModuleEvent(){}//移除模板事件public virtual void RemoveModuleEvent(){}//初始化全局事件public virtual void InitGlobalEvent(){}//移除全局事件public virtual void RemoveGlobalEvent(){}}

ViewManager

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;//视图信息类
public class ViewInfo
{public string PrefabName;//视图预制体public Transform parentTf;//父节点public BaseController controller;//视图所属控制器public int sorting_order;//显示层级顺序
}//视图管理器
public class ViewManager 
{public Transform canvasTf;//画布组件public Transform worldCanvasTf;//世界画布组件Dictionary<int,IBaseView> _opens;//开启的视图列表Dictionary<int,IBaseView> _viewCache;//视图缓存Dictionary<int,ViewInfo> _views;//注册的视图信息列表public ViewManager(){canvasTf = GameObject.Find("Canvas").transform;worldCanvasTf = GameObject.Find("WorldCanvas").transform;_opens = new Dictionary<int, IBaseView>();_views = new Dictionary<int, ViewInfo>();_viewCache = new Dictionary<int, IBaseView>();}//注册视图信息public void Register(int key,ViewInfo viewInfo){if(_views.ContainsKey(key)==false){//Debug.Log(viewInfo.PrefabName);_views.Add(key,viewInfo);}}//注册视图信息public void Register(ViewType viewType,ViewInfo viewInfo){Register((int)viewType,viewInfo);}//移除视图信息public void UnRegister(int key){if(_views.ContainsKey(key)){_views.Remove(key);}}//移除面板public void RemoveView(int key){_views.Remove(key);_viewCache.Remove(key);_opens.Remove(key);}//移除控制器中的面板视图public void RemoveViewByController(BaseController controller){foreach(var item in _views){if(item.Value.controller == controller){RemoveView(item.Key);}}}//指定视图是否打开public bool IsOpen(int key){return _opens.ContainsKey(key);}//获得指定视图public IBaseView GetView(int key){if(_opens.ContainsKey(key)){return _opens[key];}if(_viewCache.ContainsKey(key)){return _viewCache[key];}return null;}//获得指定视图,泛型public T GetView<T>(int key) where T:class,IBaseView{IBaseView view = GetView(key);if(view!=null){return view as T;}return null;}//销毁指定视图public void Destroy(int key){IBaseView oldView = GetView(key);if(oldView!=null){UnRegister(key);oldView.DestroyView();_viewCache.Remove(key);}}//关闭面板视图public void Close(int key,params object[] args){Debug.Log(key);if(IsOpen(key)==false){Debug.Log("界面不存在");return;}IBaseView view = GetView(key);if(view!=null){_opens.Remove(key);view.Close(args);_viewCache[key].Controller.CloseView(view);}}//打开指定视图面板public void Open(ViewType type,params object[] args){Open((int)type,args);}//打开指定视图面板public void Open(int key,params object[] args){IBaseView view = GetView(key);ViewInfo viewInfo = _views[key];if(view ==null){string type = ((ViewType)key).ToString();GameObject uiObj = GameObject.Instantiate(Resources.Load($"View/{viewInfo.PrefabName}"),viewInfo.parentTf) as GameObject;Canvas canvas = uiObj.GetComponent<Canvas>();if(canvas==null){canvas = uiObj.AddComponent<Canvas>();}if(uiObj.GetComponent<GraphicRaycaster>()==null){uiObj.AddComponent<GraphicRaycaster>();}//可以设置层级canvas.overrideSorting = true;//设置层级canvas.sortingOrder = viewInfo.sorting_order;//为视图添加对应脚本view = uiObj.AddComponent(Type.GetType(type)) as IBaseView;//设置视图ID;view.ViewId = key;//设置控制器view.Controller = viewInfo.controller;//添加到视图缓存_viewCache.Add(key,view);viewInfo.controller.OnLoadView(view);}if(this._opens.ContainsKey(key)==true){return;}this._opens.Add(key,view);//已经初始化过if(view.IsInit()){view.SetVisible(true);view.Open(args);viewInfo.controller.OpenView(view);}else{view.InitUI();view.InitData();view.Open(args);viewInfo.controller.OpenView(view);}}
}

这个框架中,Model和View没有直接联系,而是通过Controller来控制Model与View之间的信息通信。BaseController中SetModel让Controller和Model关联,面板在ViewManager注册,而在Register方法中让Controller和View关联。进而让Controller来控制Model与View之间的信息通信。
五、总结
MVC设计模式是一种非常有用的架构模式,它使得应用程序的结构更加清晰和易于维护。通过将数据、用户界面和业务逻辑分离,MVC模式提高了代码的可重用性和可扩展性。但MVC设计模式也有缺陷,由于将逻辑与数据分离,程序员需要了解并设计MVC之间的结构,信息通信方式等等,且这一定程度上让程序更加复杂。

相关文章:

MVC设计模式

在当今的软件开发领域&#xff0c;MVC&#xff08;Model-View-Controller&#xff09;设计模式已经成为了一种广泛使用的架构模式。它为应用程序提供了一种结构化的方法&#xff0c;将数据、用户界面和业务逻辑分开&#xff0c;从而使得应用程序更易于维护、扩展和重用。 一、…...

WSL (2103) ERROR: CreateProcessEntryCommon:493: chdir 错误解决

[TOC](WSL (2103) ERROR: CreateProcessEntryCommon:493: chdir 错误解决) 1. 错误信息 <3>WSL (2103) ERROR: CreateProcessEntryCommon:493: chdir(/mnt/d/Program Files/PowerShell/7) failed 52. 解决方法 wsl --shutdownwslrefer: https://github.com/microsoft/…...

【二、自动化测试】为什么要做自动化测试?哪种项目适合做自动化?

自动化测试是一种软件测试方法&#xff0c;通过编写和使用自动化脚本和工具&#xff0c;以自动执行测试用例并生成结果。 自动化旨在替代手动测试过程&#xff0c;提高测试效率和准确性。 自动化测试可以覆盖多种测试类型&#xff0c;包括功能测试、性能测试、安全测试等&…...

用ChatGPT来造一个ChatGPT:计算机领域智能问答系统实践(2)

在PHP语言中&#xff0c;你可以使用MySQL数据库来存储知识库&#xff0c;并使用PHP来实现系统的逻辑。以下是一个简单的示例&#xff1a; 创建数据库表&#xff1a; 首先&#xff0c;创建一个名为 computer_knowledge 的表来存储计算机知识。可以使用以下SQL语句&#xff1a;…...

Ubuntu开机自动挂载硬盘

前言&#xff1a; 因为我的电脑是WIN10 Ubuntu18.04双系统&#xff0c;且两个系统都装在C盘上&#xff0c;而D盘作为数据和代码存储盘&#xff0c;经常会开机就被访问&#xff0c;例如上一次关机前用VS Code访问D盘代码&#xff0c;然后下一次开机的时候打开VSCode发现打不开…...

vue3基础:单文件组件介绍

介绍 Vue 的单文件组件 (即 *.vue 文件&#xff0c;简称 SFC&#xff0c;全称是single file component) 是一种特殊的文件格式&#xff0c;使我们能够将一个 Vue 组件的模板、逻辑与样式封装在单个文件中。下面是一个单文件组件的示例&#xff1a; <script> export def…...

OCR字符识别:开始批量识别身份证信息

身份证信息批量识别OCR是一项解决方案&#xff0c;它能够将身份证照片打包成zip格式或通过URL地址进行提交&#xff0c;并能够识别照片中的文本信息。最终&#xff0c;用户可以将识别结果生成为excel文件进行下载。 API接口功能&#xff1a; 1. 批量识别&#xff1a;支持将多…...

php多小区智慧物业管理系统源码带文字安装教程

多小区智慧物业管理系统源码带文字安装教程 运行环境 服务器宝塔面板 PHP 7.0 Mysql 5.5及以上版本 Linux Centos7以上 统计分析以小区为单位&#xff0c;统计如下数据&#xff1a;小区总栋数、小区总户数、小区总人数、 小区租户数量、小区每月收费金额统计、小区车位统计、小…...

解决虚拟机的网络图标不见之问题

在WIN11中&#xff0c;启动虚拟机后&#xff0c;发现网络图标不见了&#xff0c;见下图&#xff1a; 1、打开虚拟机终端 输入“sudo server network-manager stop”&#xff0c;停止网络管理器 输入“cd /回车” &#xff0c; 切换到根目录 输入“cd var回车” &#xff0c;…...

【Spring类路径Bean定义信息扫描】

Spring类路径Bean定义信息扫描 1. ClassPathBeanDefinitionScanner作用2. 类声明3. 属性4. 构造器5. 扫描方法6. 真正扫描方法7. postProcessBeanDefinition8. 注册bean定义 1. ClassPathBeanDefinitionScanner作用 扫描类路径下的类注册为bean定义。2. 类声明 public class …...

Ubuntu上安装VMware+win11系统手册

Ubuntu安装vmware 下载&#xff1a; Linux 版下载地址&#xff1a;https://www.vmware.com/go/getworkstation-linux 安装&#xff1a; sudo chmod x VMware-Workstation-Full-17.5.0-22583795.x86_64.bundle 执行安装命令&#xff1a; sudo ./VMware-Workstation-Full-17.5.0…...

2024年1月12日:清爽无糖rio留下唇齿之间的香甜

友利奈绪的时间管理 2024年1月12日08:02:28进行java程序设计的上课准备 2024年1月12日08:02:44知道java的题目有18道 2024年1月12日08:43:07随机数去重比较 2024年1月12日08:54:03C语言题目最小公倍数 2024年1月12日08:58:37C语言题目二维数组变一维数组 2024年1月12日10…...

群晖Synology Drive同步文件时过滤指定文件夹“dist“, “node_modules“

群晖Synology Drive同步文件时过滤指定文件夹"dist", “node_modules” mac用户 安装Synology Drive创建同步任务修改Synology Drive配置 打开/Users/[用户名]/Library/Application Support/SynologyDrive/data/session/[同步任务序号&#xff0c;第一个同步任务就…...

小程序中滚动字幕

需求&#xff1a;在录像时需要在屏幕上提示字幕&#xff0c;整体匀速向上滚动 html部分&#xff1a; <view class"subtitles_main"><view style"font-size:34rpx;color: #fff;line-height: 60rpx;" animation"{{animation}}">人生的…...

MySQL中约束是什么?

&#x1f389;欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克&#x1f379; ✨博客主页&#xff1a;小小恶斯法克的博客 &#x1f388;该系列文章专栏&#xff1a;重拾MySQL &#x1f379;文章作者技术和水平很有限&#xff0c;如果文中出现错误&am…...

若依在表格中如何将字典的键值转为中文

文章目录 一、需求&#xff1a;二、问题解决步骤1、给需要转换的列绑定formatter属性2、获取字典项3、编写formatter属性绑定的方法 一、需求&#xff1a; 后端有时候返回的是字典的键值&#xff0c;在前端展示时需要转成中文值 后端返回的是dictValue&#xff0c;现在要转换…...

用笨办法-刻意练习来提高自己的编程能力

尝试了很多学习方法&#xff0c;企图快速提高编程能力&#xff0c;但最终发现&#xff0c;唯有老老实实刻意练习1&#xff0c;在辛苦与时间积累下&#xff0c;逐渐提升能力&#xff0c;才是最有效的方式。 将自己的笨办法总结了一下&#xff0c;主要包含7个步骤&#xff1a; …...

FineBI报表页面大屏小屏自适应显示问题

大屏正常显示 显示正常 小屏BI自适应显示 存在遮挡字体情况 小屏浏览器缩放显示 等比缩放后显示正常...

NAND Separate Command Address (SCA) 接口命令解读

CA output packet和CA input packet是Separate Command Address (SCA) NAND接口协议中用于命令和地址传输的关键数据结构。 CA Input Packet: 在SCA接口中&#xff0c;输入到NAND器件的命令和地址信息被组织成并行至串行转换的CA&#xff08;Command and Address&#xff09;输…...

Git的简单使用说明

Git入门教程 git的最主要的作用&#xff1a;版本控制&#xff0c;协助开发 一.版本控制分类 ​​ 1.本地版本控制 ​​ 2.集中版本控制 ​​ 所有的版本数据都存在服务器上&#xff0c;用户的本地只有自己以前所同步的版本&#xff0c;如果不连网的话&#xff0c;用户就看不…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)

2025年能源电力系统与流体力学国际会议&#xff08;EPSFD 2025&#xff09;将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会&#xff0c;EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

基于Flask实现的医疗保险欺诈识别监测模型

基于Flask实现的医疗保险欺诈识别监测模型 项目截图 项目简介 社会医疗保险是国家通过立法形式强制实施&#xff0c;由雇主和个人按一定比例缴纳保险费&#xff0c;建立社会医疗保险基金&#xff0c;支付雇员医疗费用的一种医疗保险制度&#xff0c; 它是促进社会文明和进步的…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

视频字幕质量评估的大规模细粒度基准

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用&#xff0c;因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型&#xff08;VLMs&#xff09;在字幕生成方面…...

python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

基于Springboot+Vue的办公管理系统

角色&#xff1a; 管理员、员工 技术&#xff1a; 后端: SpringBoot, Vue2, MySQL, Mybatis-Plus 前端: Vue2, Element-UI, Axios, Echarts, Vue-Router 核心功能&#xff1a; 该办公管理系统是一个综合性的企业内部管理平台&#xff0c;旨在提升企业运营效率和员工管理水…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...