当前位置: 首页 > 综合

PMVC使用实战

日期:2023-07-31 20:15:26 来源:哔哩哔哩

按照之前的学习记录整理方法,这一次我也会将pmvc的学习记录整理成知识点和实践两个部分,可能会有效果展示部分.


(相关资料图)

1.知识点

主管给了一份写的很清晰的文档,我只能是简单总结一下了

概述

PureMVC,下称PMVC,是一个MVC框架.MVC是Model-View-Controller的缩写,这是一个经常使用的架构.大二暑假做高科实习的时候做web后端开发就是用的SpringMVC,当时只是停留在会使用的表面.

MVC的目的是分离数据层/表现层和逻辑层,降低耦合性

PMVC将应用程序分为三层四个模块:Model,View,Controller,每一层的具体实现都是一个单例,第四个模块facade负责各层之间的通信

Facade初始化Model,View,Controller,三个单例,并且能访问各层类的public方法,上面说到这四个模块的实现都是单例,facade就是负责实例化另外三个单例的,它是整个框架的最上层,同时也负责MVC三个模块的通信.Facade的设计是一个典型的外观模式(毕竟它都叫"Facade-表面"这个名字了)

实际使用时,开发者继承一个Facade,添加自己需要的属性和方法,然后就可以开始用了.

观察者模式

观察者模式是一个设计模式,也是facade主要用到的设计模式.引用菜鸟教程上的解释:

观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,当一个对象的状态发生改变时,其所有依赖者都会收到通知并自动更新。

当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。

PMVC封装了一个方法Notification来从M,V,C发送通知,用来触发执行命令,这套机制的实现由PMVC实现,我们不需要具体的了解

(重要)PMVC中组件的耦合与依赖关系

commandcommand的权限很高,但它的创建是被限制的.

command可以发送Notification给其他组件,可以直接获取和操作mediator和proxy,可以注册销毁和检查proxy,mediator和command;

mediatormediator主要做三件事:修改自己的视图组件,检查或修改proxy的属性(这点很重要,牢记medaitor可以操控proxy修改proxy),发送notification给其他mediator或者command(重要,牢记proxy不接收消息)

proxyproxy可能专门管理一个本地创建的复杂的数据对象,也可以理解为,proxy封装了一个数据对象.

我对model&proxy,view&mediator,controller&command的理解

这三组东西似乎总是两两绑定,我一直不理解具体用的时候是个什么关系,比如说,我设计模块的时候,model/view/controller是要单独写个类出来吗还是说和对应的proxy/mediator/command绑在一起.

现在我觉得,m/v/c三个东西是相对抽象的,它们有具体的凭依的模块,举例来说,一般会写一个data类描述某个模块,在fgui里面,一个继承Gcomponent的组件类就是view,但是它们的管理是由pro/med/com三个层级管理者来执行的,mvc三个模块完全依赖于各自的管理者.从这个角度来说,我甚至不用单独写个data类,反正data的属性完全封装,即使单独写类也不会给除了proxy以外的任何模块使用.

2.案例分析

找到一个csdn用户"嘿呀好气"的简单教程,按理说已经简单到不需要做记录了,但是我毕竟是个新手,简单写写有助于理解

地址

/kirikayakazu/article/details/89788451

结构上分为以下几个内容:

实体类

Proxy

Mediator

Command

Facade

继承component的脚本组件

我的疑问:既然proxy对应了model层,为什么还要有单独的实体类,把他们放在一起可以吗,这样做应该是为了降低耦合,不过实体类应该只依赖于proxy才对,没必要降低耦合.

emm还是有必要的,这样结构更清晰,可读性强

实体类存放一格模块/对象的描述,不用解释

Proxymodel层的数据操纵类,能够直接处理实体类,在这里要做:

注册该模块名字:继承属性proxyName

设置单例和单例获取的方法getInstance();

构造函数;

实体处理函数;

Mediator表现层管理类,似乎没有和View组件分离的必要,在这里要做:

单例和获取单例方法

构造函数(注册UI组件的逻辑在这里进行);

监听回调函数,主要做发送消息(Notification)的工作;

注册感兴趣的消息(notification):继承函数listNotificationInterests();

消息处理函数;

Command控制层管理类

单例和获取单例方法

逻辑处理函数:execute(notification:)

Facade架构的最上层.管理mvc三层

单例和获取单例

构造函数,其中要做:注册三个层级的单例.

3.实战:使用PMVC重构cocos小游戏《围住神经猫》

之前已经进行过一次cocos开发了,因为使用和加载资源的方式没变(还是fgui)所以不再赘述

先前项目记录:

/read/cv25420626

相比之前,有了一些进步:

既然使用了MVC框架,代码结构耦合度肯定是更低了,结构也更加分明(但是明显复杂了)

进一步优化了代码,原先的一些模块在拆分结构以后发现居然没用了,这说明之前肯定是有冗余的

这次重构给我的感觉是:结构反而变复杂了.项目的模块变多了不少,以至于我可能需要画张图来表现我这个项目的mvc架构是怎么样的.

图样如下:

Proxy:

ProxyGameScene管理游戏有关的私有核心数据(公共数据写在静态数据类中,可被自由访问),即GameData,包含dataMatrix和cat数据等

Mediator

MediatorMainMenu负责主菜单的界面,获取资源,添加按钮监听并且可以处理loadscene的消息,也可以发送loadscene消息

MediatorGame,负责游戏主逻辑,可以处理loadscene和resetgame消息,可以发送loadscene,findpath消息

MediatorDialog,负责胜利或失败对话框的逻辑,可以处理showdialog消息,可以发送loadscene,resetgame消息

Command

loadsceneCommand决定加载哪个场景(因为我不再使用多场景,所以这里说的是加载哪个场景的UI界面),加载完后会发送resetscene消息,使得舞台初始化

ResetGameCommand发送重置游戏的消息,使得游戏场景更新关卡,并初始化关卡

CommandShowDiaBox决定加载哪个对话框,然后给MediatorDialog发送消息,加载对话框

CommandFindPath最复杂的一个command,要在玩家点击以后,根据ProxyGameScene的数据变化求出猫的状态,游戏进行状态和猫的下一个落点等一些列数据.

现在看看我是怎么做的

构建Facade类和启动器

众所周知cocos是基于节点运作的,除非是静态类或者是被别的脚本new出来,不然要把脚本挂载到节点上才能实例化.Facade肯定不能继承脚本类,所以要有一个启动器把他实例化出来

初始化类,顺便在这里以静态的方式提前加载资源包

我的Facade类:AppFacade继承了Facade,并在此之上添加我的逻辑,主要是注册消息名称和三个层级的模块\

Proxy和Data(在这里用data类封装了抽象的model)

首先是Data,这里的data内容非常少,这也是我拆分架构以后才发现的,这个小游戏用到的数据其实是非常少的

然后是Proxy,Proxy只提供了一些操纵数据的方法供外部调用.

为什么这里只有一个Proxy,而mediator却有三个,这是因为主界面和对话框的Mediator几乎没有任何数据可言,就是纯UI界面,所以完全不需要Proxy来管理数据.

Mediator

这里只以MediatorGame为例,因为正如上面所说,另外两个Mediator太简单了.

可以看到mediator的成员都是视图组件

可以看到Mediator能够发送和接收消息,并根据不同的消息作处理

Command只有在使用的时候才会出现,使用完毕以后会消失,command和notification是一对一的关系,一个command不能绑定多个消息,一个消息也不能被多个command绑定,否则会有一个不监听消息.

command不需要调用,因为它是和消息绑定的,所以想要执行command,直接发送对应的消息就可以

command有一个继承方法execute,它会在command被激活是调用,这也是command的核心方法.

最后效果不再演示,和先前是一样的

标签:

热门推荐

猜你喜欢

市场