欢迎光临散文网 会员登陆 & 注册

学习使用C#语言构建MVC架构的笔记

2022-07-11 19:14 作者:流年夏华  | 我要投稿

前置知识(来源于网络):

关于MVC:MVC 模式代表 Model-View-Controller(模型-视图-控制器) 模式。这种模式用于应用程序的分层开发。

Model(模型) - 模型代表一个存取数据的对象;

View(视图) - 视图代表模型包含的数据的可视化。

Controller(控制器) - 控制器作用于模型和视图上。它控制数据流向模型对象,并在数据变化时更新视图。它使视图与模型分离开。

MVC的历史:MVC 模式由 Trygve Reenskaug 在 1978 年提出[,是施乐帕罗奥多研究中心(Xerox PARC)在 20 世纪 80 年代为程序语言Smalltalk 发明的一种软件设计模式。

MVC模式的作用:MVC 模式的目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。

MVC模式的改良:

MVP模式:在上个世纪90年代,IBM旗下的子公司Taligent在用C/C++开发一个叫CommonPoint的图形界面应用系统的时候提出来的。

MVVM模式:MVVM模式最早是微软公司提出,并且了大量使用在.NET的WPF和Sliverlight中。2005年微软工程师John GosSman在自己的博客上首次公布了MVVM模式。

三层架构:三层架构是一种程序设计结构,使用分层式结构将整个应用拆分为三层:最上层:表示层。中间层:业务逻辑层。最底层:数据访问层。三层都依赖于实体类,因为数据传输通过实体类来传输。上层依赖于下层,下层不依赖于上层,但下层需要向上层返回结果。

正文:

一般的程序采用类似逐过程的开发方式,即“产生需求——构造逻辑——添加组件——改善逻辑——添加组件...”,最终结果是产出一坨意大利面条式代码,流程混乱难以维护和复用。一次偶然的机会我在网上看到了关于MVC模式的介绍,看完后觉得应该尝试一下,但是苦于网络上缺乏C#及Godot引擎的MVC模式代码,于是自己动手实现(姑且算是)了一个MVC模式。

参考网上的资料,MVC模式的核心在于UI、逻辑、数据的解耦,为了达成三方的解耦,我选择了单例模式及接口作为模块间引用的方式,以后有机会的话再考虑MVVM使用XAML双向绑定的方法。

这次的例子是Godot引擎,需求是“按下按键后角色移动”,这个需求应该是游戏开发最常见的需求之一了,实现起来也比较简单。

首先是搭建场景,创建一个Player节点(Godot里叫Node,等于Unity里的GameObject)

在Player节点上挂载PlayerView脚本。

在这里也展示一下MVC模式的脚本结构:

PlayerView.cs是Player的View层,负责接受按键事件并返回。

Move.cs是Player的Controller层,负责逻辑计算。为了防止频繁触发new产生内存垃圾,这里使用了单例模式。

PlayerEntity.cs是Player的Model层,负责构建Player的数据模型。因为Player对象全局唯一,这里使用了单例模式。(目前没有实现数据库,所以现在数据直接放在Model层内)

Iname.cs, ISpeed.cs, IPlayer.cs是Model接口,Model层实现Model接口,Controller层调用Model接口间接访问Model层数据。

IPosition.cs比较特殊,它是PlayerView的接口。因为PlayerView既是Player的View层,它也控制Player节点的数据,所以从后一个角度看它也可以算是一个特殊的Model,也需要实现一个接口来传递节点的数据。

具体实现代码:

观察代码,按键事件产生后先由PlayerView.cs接收事件,在内部判断具体是按下了哪个按键,并根据按键是W|S|A|D分别调用Move.cs的MovingUp|MovingDown|MovingLeft|MovingRight方法,并传入实现ISpeed接口的PlayerEntity单例与实现IPosition接口的自身;Move.cs的方法接入传参后通过ISpeed获取PlayerEntity的Speed、通过IPosition获取PlayerView的Position,进行运算后再通过IPosition向游戏引擎返回修改后的Position。

架构优点:方便扩展修改:在写这篇笔记的过程中代码还优化了好几次,我自己感觉不管是修改API还是扩展API都比之前的面条式代码方便许多,例如在写文章之前MovingUp/Down/Left/Right之前是Moving,Moving方向的判断放在了Controller层,后来我把方向判断的逻辑放在了View层也并不影响PlayerView、PlayerEntity的代码。

架构缺点:

1.资料难找:虽然MVC架构是 20 世纪 80 年代提出的,但是直到现在要找一个简单清晰的MVC代码例子仍然不方便,尤其是C#语言(Java圈对架构、设计模式的热衷让人羡慕)。

2.脚本数量多:为了实现按键移动,在例子里创建了6个脚本(IName.cs其实并非必须文件,它存在的意义是体现C#接口可通过接口的多重继承组合成新的接口来服务Model层不同的业务需求),程序需求增加的情况下,脚本文件数量的增长可能会超过预期。

3.逻辑混乱:没错,是逻辑混乱,虽然MVC将数据与逻辑分离,但也产生了一个问题:“逻辑是放在Controller层还是放在View层?”在写这篇文章之前,这个例子里也出现了把捕获按键事件和判断具体按键分开的情况,最后我将两个逻辑合并到View层中,但也多少违背了“Controller层负责逻辑”的原则,后面可能会分离出一个类似“InputEventKeyController”这样的Controller类,但那也是后话了。

总结:程序开发没有银弹,有的是对“分离变与不变”原则的各种实践。缺乏设计与过度设计都不可取,只有在具体的开发环境中才能体会到原则的可贵与实践的困难。


学习使用C#语言构建MVC架构的笔记的评论 (共 条)

分享到微博请遵守国家法律