C#架构-客户端MVP揭秘(标题正确版本)
ccwgpt 2024-10-25 10:50 36 浏览 0 评论
我在C#架构-客户端MVP揭秘一文中讲到了我所知道的MVC的历史以及它构建出来的初衷,其中核心就是构建model层和view层的对应关系。数据抽象和显示抽象一一对应起来,操作数据以便操作显示,显示改变也能改变数据,那么两者之间就紧密关联起来了。说到这里大家会不会觉得这个和vuejs或者wpf中的MVVM架构很像,用过vue或者wpf的都知道显示和数据是紧密联系的。
比如说我保存一个单据,我不再需要再次获取界面的数据然后调用业务层了,因为显示数据已经和model层绑定了,那么我直接可以拿model层数据去保存单据就行了。那或许你就有疑问了,那MVVM和MVC有什么区别呢?答案就是MVC view层和model层的关系是手动联系的,需要写代码的,而MVVM中他们的绑定关系交给了框架去做了,就是这么一点区别。这一点上MVC和MVP是一样的,唯一的区别是MVP里面model层不直接和view层绑定关系,而是把这个关系放到了controller层里面去了,也就是model层数据变化先传递到controller层,然后控制层把数据变化转到view层。类似下面这个图所示。
这么做有什么好处呢?就是彻底解放view层,view层和model没有直接的关系了,都是通过控制层进行数据传递,这样view层可以作为一个组件进行复用,不会受到model层的影响。
光说不练假把式,还是通过一个C#例子进行举例,然后主要分析一下MVP和MVC的区别,以及从高内聚,松耦合,可扩展这三个点去分析一下MVP的优点。
请看图2,目的是输入数字,点击显示按钮,label1显示这个数字,点击自增,label1自增显示。例子和C#架构-客户端MVP揭秘这篇文章是一样的,只是实现方式从MVC改成了MVP。
图3是MVP中P层,也就是Presenter层,后续称为"主导器"。主导器和MVC中的Controller一样,属于交互作用,用于处理用户输入交互,消息处理交互等。然后把View层数据传递到Model层建立一对一关系,当View层数据变化也通过主导器传递到View层显示。请看图3代码,
MainPresenter主导器构造函数两个形参,一个是IMainView,一个是IModel。前者是MVP中的View层,后者是MVP里面的M层。
请看图4的IMainView定义,这个接口定义了两个事情一个方法,DisplayValue和IncrementValue两个事件,用于主导器订阅前端的"显示"按钮和"自增"按钮这两个事件,图3可以看出来订阅过程,MainPresenter主导器对DisplayValue这个事件绑定了View_DisplayValue这个方法,其中执行了this.model.SetValue(e.value)和this.model.DisplayValue()这两个方法。
图5 可以看到FrmMain主界面实现了IMainView接口,触发了图4的两个事件。
然后事件就传递到了MainPresenter主导器,执行View_DisplayValue这个方法。
图6是Model层代码,首先SetValue方法是赋值,DisplayValue方式是显示,显示的方式是触发Changed事件,这个事件在哪里订阅呢,在MainPresenter主导器里面订阅,请看图3代码
在MainPresenter主导器构造函数里面,这句this.model.Changed+=Model_Changed
请看Model_Changed方法体,执行了this.view.Display(e.newval);这句代码,请看图5,把数据展示。
同理在看一下点击"自增"按钮的过程,首先触发这个IncrementValue事件,把事件传递到主导器中,主导器订阅了这个事件,执行this.model.Increment();Model层对应的操作无非是value++,然后触发Changed事件,把事件传递到主导器中,然后主导器执行View中的方法
this.view.Display(e.newval);
我们看看是怎么创建主导器的。请看图7
图7代码非常的好明白,无非就是创建FrmMain窗体对象和MvpModel Model对象然后创建主导器对象,把三者关联起来。
这里的代码说实话没有很难看懂的代码,但是和我们平时写的代码有区别,在没有任何设计的情况下,我们总是喜欢按照思维顺序的方式去写代码,也就是三层架构的方式去写,不会单独去写交互层和model层。但是为什么要这么做,这么做的好处有什么,我们开篇说好处是高内聚,松耦合,可扩展,接下来我们就通过这三点总结一下。
我们再看一下MainFrm代码。
View层只实现了IMainView接口,我们暂时不用理会FrmBase这个基类,我们就当是继承了Form。继承了IMainView接口,然后传递触发了事件,以及显示数据,没有其他的交互逻辑了,View层只做展示,不做别的事情,所谓别的事情就是不会去调用Bll层去查数据,也不会写一些交互逻辑,比如说验证数据的准确性,这些都在主导器完成,这样有什么好处呢?好处就是高内聚和松耦合。实现单一职责这个设计原则,也就是高内聚,因为这里就是单单显示代码以及事情的传递,非常清楚,不干别的工作。
通过接口和主导器进行交互的好处就是,如果项目比较大,人员比较多,就可以做界面和做交互的事情分开不同的人做,他们唯一需要共同商讨的就是这个IMainView事件怎么定义就行了。做界面的不需要知道主导器是怎么实现的,怎么定义的,怎么调用,都不需要知道。那么这个View层就变成了用户控件一样,可以匹配不同的主导器,主导器怎么变都可以,只是实现共同定义的IMainFrm接口就行了。
请看图7的代码,完全可以创建多个主导器,比如一个主导器用于处理UI交互,一个主导器处理Hook事件,也就是比如扫码事件,快捷键事件等等,一个主导器处理Mqtt事件交互。
这样就实现了可扩展的好处。因为View层代码很少了,大部分代码转移到了主导器里面去了,那么主导器代码就会变得很多很杂,除了通过分部代码把代码拆分,也可以通过建立多个子主导器进行分解代码,那么项目大了人员多了的时候主导器都可以分给不同的人去做。
伪代码就变得如图9这样。
这里还有一个好处就是Model层,一个Model层可以控制多个视图。我们知道Model层的构建初衷就是为了和View层数据一一对应,显示抽象和数据抽象关联在一起,两者相互影响,那数据保存的时候不需要重新从界面上获取值,而是直接拿Model层的数据去保存就行了,显示数据,不需要拿到控件进行展示,而是直接将Model的值改掉就会同步改掉界面上的数据了。
如果存在不同的界面对应的Model层数据是一样的,我们就可以通过一个Model绑定多个主导器,从而同时控制不同的界面。我们想一想有没有这种场景。比如登入界面的用户名,有没有可能除了登录界面有用,登入之后的主界面也需要用到呢,当然有这种可能性,那么我们可以定义一个Model,绑定多个主导器,从而控制多个界面显示。这里的关键点,为什么可以做到这点,就是因为我们是通过主导器订阅Model事件的方式来触发数据变化展示到界面上的。那么多个主导器订阅一个model事件,当触发一个这个事件,可以传递给多个主导器。这就是为什么Model层要通过触发事件的方式传递出去的原因。
我们再来看看这个图
请看图10,再结合我们上面所讲。这个图说明的很明白,第一点就是View和Model是没有任何关联的,View和Presenter是通过接口方式交互的,这就让View独立提供了条件,看红色的步骤,第1步是通过Presenter层订阅View事件进行事件传递,同时可以做到将Presenter进行拆分,因为是通过接口交互的,第2步是Presenter直接调用Model方法,第3步Model传递数据给Presenter是通过Presenter订阅Model事件方式传递的,这样的好处就是一个Model可以绑定多个Presenter,从而绑定多个界面。第四步是通过接口方式把数据传递给View层进行展示。
MVP和MVC的区别也可以得出了,我们看这篇文章C#架构-客户端MVP揭秘和本文进行对比就知道了,MVC中View层还是会和Model层有耦合,这样导致View无法真正的独立。MVP解决了这个问题。
相信我们上述讲解就明白了MVP为什么这么设计。
接下来我们优化一下代码,让创建Presenter对象的方式更加方便好看一点。
直接发代码
请看图11,FrmMain绑定特性IMainPresenter这个主导器接口。
请看图12,FrmMain 继承了这个FrmBase,其中构造函数执行了
_controller.ControllerBinding(this)
获取界面特性,获取主导器接口,然后实例化这个主导器,这里实例化的过程是用DI的方式。
这样就可以实例化主导器实例。
图13 presenter.BindingView(view);这句话就给主导器绑定了View层。
这样入口只要初始化DI就行了。具体DI里面做了什么,因为还没有单独写DI的文章
,请看文章C#核心-反射揭秘1发射系列文章。
这里这么处理的好处就是Model层需要引用bll,dal层只需要引用接口方式就能使用了。
以上MVP是指Passive View,意思就是View层完全独立开的。
Supervising Controller 这个模式是指model层数据除了通过主导器传到view还可以直接类似MVC的方式让View定义Model事件,但是一般MVP都是使用Passive View,说明Supervising Controller这个实战还是有问题的,这里就不讲诉这个
Supervising Controller了。
MVVM和MVP的区别就在于在MVP Passive View这个基础之上,Model和View的数据交互的过程让框架去做了,我们从上面可以看到我们都是手写方式去做这个过程的。
下一篇文章会通过C#来实战一下MVVM,并说明它的好处
相关推荐
- 一个基于.Net Core遵循Clean Architecture原则开源架构
-
今天给大家推荐一个遵循CleanArchitecture原则开源架构。项目简介这是基于Asp.netCore6开发的,遵循CleanArchitecture原则,可以高效、快速地构建基于Ra...
- AI写代码翻车无数次,我发现只要提前做好这3步,bug立减80%
-
写十万行全是bug之后终于找到方法了开发"提示词管理助手"新版本那会儿,我差点被bug整崩溃。刚开始两周,全靠AI改代码架构,结果十万行程序漏洞百出。本来以为AI说没问题就稳了,结果...
- OneCode低代码平台的事件驱动设计:架构解析与实践
-
引言:低代码平台的事件驱动范式在现代软件开发中,事件驱动架构(EDA)已成为构建灵活、松耦合系统的核心范式。OneCode低代码平台通过创新性的注解驱动设计,将事件驱动理念深度融入平台架构,实现了业务...
- 国内大厂AI插件评测:根据UI图生成Vue前端代码
-
在IDEA中安装大厂的AI插件,打开ruoyi增强项目:yudao-ui-admin-vue31.CodeBuddy插件登录腾讯的CodeBuddy后,大模型选择deepseek-v3,输入提示语:...
- AI+低代码技术揭秘(二):核心架构
-
本文档介绍了为VTJ低代码平台提供支持的基本架构组件,包括Engine编排层、Provider服务系统、数据模型和代码生成管道。有关UI组件库和widget系统的信息,请参阅UI...
- GitDiagram用AI把代码库变成可视化架构图
-
这是一个名为gitdiagram的开源工具,可将GitHub仓库实时转换为交互式架构图,帮助开发者快速理解代码结构。核心功能一键可视化:替换GitHubURL中的"hub...
- 30天自制操作系统:第六天:代码架构整理与中断处理
-
1.拆开bootpack.c文件。根据设计模式将对应的功能封装成独立的文件。2.初始化pic:pic(可编程中断控制器):在设计上,cpu单独只能处理一个中断。而pic是将8个中断信号集合成一个中断...
- AI写代码越帮越忙?2025年研究揭露惊人真相
-
近年来,AI工具如雨后春笋般涌现,许多人开始幻想程序员的未来就是“对着AI说几句话”,就能轻松写出完美的代码。然而,2025年的一项最新研究却颠覆了这一期待,揭示了一个令人意外的结果。研究邀请了16位...
- 一键理解开源项目:两个自动生成GitHub代码架构图与说明书工具
-
一、GitDiagram可以一键生成github代码仓库的架构图如果想要可视化github开源项目:https://github.com/luler/reflex_ai_fast,也可以直接把域名替换...
- 5分钟掌握 c# 网络通讯架构及代码示例
-
以下是C#网络通讯架构的核心要点及代码示例,按协议类型分类整理:一、TCP协议(可靠连接)1.同步通信//服务器端usingSystem.Net.Sockets;usingTcpListene...
- 从复杂到优雅:用建造者和责任链重塑代码架构
-
引用设计模式是软件开发中的重要工具,它为解决常见问题提供了标准化的解决方案,提高了代码的可维护性和可扩展性,提升了开发效率,促进了团队协作,提高了软件质量,并帮助开发者更好地适应需求变化。通过学习和应...
- 低代码开发当道,我还需要学习LangChain这些框架吗?| IT杂谈
-
专注LLM深度应用,关注我不迷路前两天有位兄弟问了个问题:当然我很能理解这位朋友的担忧:期望效率最大化,时间用在刀刃上,“不要重新发明轮子”嘛。铺天盖地的AI信息轰炸与概念炒作,很容易让人浮躁与迷茫。...
- 框架设计并不是简单粗暴地写代码,而是要先弄清逻辑
-
3.框架设计3.框架设计本节我们要开发一个UI框架,底层以白鹭引擎为例。框架设计的第一步并不是直接撸代码,而是先想清楚设计思想,抽象。一个一个的UI窗口是独立的吗?不是的,...
- 大佬用 Avalonia 框架开发的 C# 代码 IDE
-
AvalonStudioAvalonStudio是一个开源的跨平台的开发编辑器(IDE),AvalonStudio的目标是成为一个功能齐全,并且可以让开发者快速使用的IDE,提高开发的生产力。A...
- 轻量级框架Lagent 仅需20行代码即可构建自己的智能代理
-
站长之家(ChinaZ.com)8月30日消息:Lagent是一个专注于基于LLM模型的代理开发的轻量级框架。它的设计旨在简化和提高这种模型下代理的开发效率。LLM模型是一种强大的工具,可以...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- 框架图 (58)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- springmvc框架 (49)
- 分布式事务框架 (65)
- scrapy框架 (56)
- shiro框架 (61)
- 定时任务框架 (56)
- java日志框架 (61)
- mfc框架 (52)
- abb框架断路器 (48)
- beego框架 (52)
- java框架spring (58)
- grpc框架 (65)
- tornado框架 (48)
- 前端框架bootstrap (54)
- orm框架有哪些 (51)
- 知识框架图 (52)
- ppt框架 (55)
- 框架图模板 (59)
- 内联框架 (52)
- cad怎么画框架 (58)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)