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设计模式
在当今的软件开发领域,MVC(Model-View-Controller)设计模式已经成为了一种广泛使用的架构模式。它为应用程序提供了一种结构化的方法,将数据、用户界面和业务逻辑分开,从而使得应用程序更易于维护、扩展和重用。 一、…...
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/…...
【二、自动化测试】为什么要做自动化测试?哪种项目适合做自动化?
自动化测试是一种软件测试方法,通过编写和使用自动化脚本和工具,以自动执行测试用例并生成结果。 自动化旨在替代手动测试过程,提高测试效率和准确性。 自动化测试可以覆盖多种测试类型,包括功能测试、性能测试、安全测试等&…...
用ChatGPT来造一个ChatGPT:计算机领域智能问答系统实践(2)
在PHP语言中,你可以使用MySQL数据库来存储知识库,并使用PHP来实现系统的逻辑。以下是一个简单的示例: 创建数据库表: 首先,创建一个名为 computer_knowledge 的表来存储计算机知识。可以使用以下SQL语句:…...
Ubuntu开机自动挂载硬盘
前言: 因为我的电脑是WIN10 Ubuntu18.04双系统,且两个系统都装在C盘上,而D盘作为数据和代码存储盘,经常会开机就被访问,例如上一次关机前用VS Code访问D盘代码,然后下一次开机的时候打开VSCode发现打不开…...
vue3基础:单文件组件介绍
介绍 Vue 的单文件组件 (即 *.vue 文件,简称 SFC,全称是single file component) 是一种特殊的文件格式,使我们能够将一个 Vue 组件的模板、逻辑与样式封装在单个文件中。下面是一个单文件组件的示例: <script> export def…...
OCR字符识别:开始批量识别身份证信息
身份证信息批量识别OCR是一项解决方案,它能够将身份证照片打包成zip格式或通过URL地址进行提交,并能够识别照片中的文本信息。最终,用户可以将识别结果生成为excel文件进行下载。 API接口功能: 1. 批量识别:支持将多…...
php多小区智慧物业管理系统源码带文字安装教程
多小区智慧物业管理系统源码带文字安装教程 运行环境 服务器宝塔面板 PHP 7.0 Mysql 5.5及以上版本 Linux Centos7以上 统计分析以小区为单位,统计如下数据:小区总栋数、小区总户数、小区总人数、 小区租户数量、小区每月收费金额统计、小区车位统计、小…...
解决虚拟机的网络图标不见之问题
在WIN11中,启动虚拟机后,发现网络图标不见了,见下图: 1、打开虚拟机终端 输入“sudo server network-manager stop”,停止网络管理器 输入“cd /回车” , 切换到根目录 输入“cd var回车” ,…...
【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 下载: Linux 版下载地址:https://www.vmware.com/go/getworkstation-linux 安装: sudo chmod x VMware-Workstation-Full-17.5.0-22583795.x86_64.bundle 执行安装命令: 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/[同步任务序号,第一个同步任务就…...
小程序中滚动字幕
需求:在录像时需要在屏幕上提示字幕,整体匀速向上滚动 html部分: <view class"subtitles_main"><view style"font-size:34rpx;color: #fff;line-height: 60rpx;" animation"{{animation}}">人生的…...
MySQL中约束是什么?
🎉欢迎您来到我的MySQL基础复习专栏 ☆* o(≧▽≦)o *☆哈喽~我是小小恶斯法克🍹 ✨博客主页:小小恶斯法克的博客 🎈该系列文章专栏:重拾MySQL 🍹文章作者技术和水平很有限,如果文中出现错误&am…...
若依在表格中如何将字典的键值转为中文
文章目录 一、需求:二、问题解决步骤1、给需要转换的列绑定formatter属性2、获取字典项3、编写formatter属性绑定的方法 一、需求: 后端有时候返回的是字典的键值,在前端展示时需要转成中文值 后端返回的是dictValue,现在要转换…...
用笨办法-刻意练习来提高自己的编程能力
尝试了很多学习方法,企图快速提高编程能力,但最终发现,唯有老老实实刻意练习1,在辛苦与时间积累下,逐渐提升能力,才是最有效的方式。 将自己的笨办法总结了一下,主要包含7个步骤: …...
FineBI报表页面大屏小屏自适应显示问题
大屏正常显示 显示正常 小屏BI自适应显示 存在遮挡字体情况 小屏浏览器缩放显示 等比缩放后显示正常...
NAND Separate Command Address (SCA) 接口命令解读
CA output packet和CA input packet是Separate Command Address (SCA) NAND接口协议中用于命令和地址传输的关键数据结构。 CA Input Packet: 在SCA接口中,输入到NAND器件的命令和地址信息被组织成并行至串行转换的CA(Command and Address)输…...
Git的简单使用说明
Git入门教程 git的最主要的作用:版本控制,协助开发 一.版本控制分类 1.本地版本控制 2.集中版本控制 所有的版本数据都存在服务器上,用户的本地只有自己以前所同步的版本,如果不连网的话,用户就看不…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
oracle与MySQL数据库之间数据同步的技术要点
Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异,它们的数据同步要求既要保持数据的准确性和一致性,又要处理好性能问题。以下是一些主要的技术要点: 数据结构差异 数据类型差异ÿ…...
华为OD机试-食堂供餐-二分法
import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...
python如何将word的doc另存为docx
将 DOCX 文件另存为 DOCX 格式(Python 实现) 在 Python 中,你可以使用 python-docx 库来操作 Word 文档。不过需要注意的是,.doc 是旧的 Word 格式,而 .docx 是新的基于 XML 的格式。python-docx 只能处理 .docx 格式…...
《基于Apache Flink的流处理》笔记
思维导图 1-3 章 4-7章 8-11 章 参考资料 源码: https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...
LabVIEW双光子成像系统技术
双光子成像技术的核心特性 双光子成像通过双低能量光子协同激发机制,展现出显著的技术优势: 深层组织穿透能力:适用于活体组织深度成像 高分辨率观测性能:满足微观结构的精细研究需求 低光毒性特点:减少对样本的损伤…...
Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...
