不懂PureMVC框架问题?深入解读看完必会(上)

<码字不易,麻烦点点关注支持一下哟!>

简易UI框架

1.UI框架核心方法
  • BaseUI会记录UI的名字(枚举)和Controller用来将UI与具体操作方法解耦
  • UIManger利用字典记录所有的UI组件,然后提供一些打开关闭UI的方法
  • EventManager(事件系统)来实现模块与模块之间的交互,事件系统也分很多种实现方式,都是观察者设计模型的典型应用,利用一个关键字注册多个方法,然后在利用这个关键字激活调用已经住的方法。也是C#中委托的一种典型用法。广播形式、通知形式等。
2.UI框架拓展方法
  • ResourcesManager(资源管理器),封装一些加载Resources资源的方法,同步加载,异步加载,加载并实例化等方式的方法。
  • DataHelper(数据解析器),对Xml、Json(LitJson、JsonFX)、Protobuf等数据格式序列化与反序列化插件的进一步封装,方便调用。
  • Common Extension(公共拓展组件)利用泛型和拓展方法对Unity中的方法进行进一步的封装,加快开发速度。
  • Singleton(单例)
  • NetworkManager,负责与后台数据的下载、上传。
3.简易UI框架的优缺点
  • 容易上手使用
  • 针对C#新手相对容易理解
  • 只适合很小的项目
  • 拓展性很差
  • 逻辑会堆在MonoBehaviour的脚本下,效率降低

躺过上面这种简易UI框架的坑之后,才会意识到一个大一点的项目,或者是多人合作开发的项目,一定要有一个较为牢靠的框架做为基础,在Unity中有几种常见的框架,也是从传统的经典矿建拓展过来的。PureMVC(MVC框架),StrangeIOC(MVCS框架),uFrame(MVVM框架)。

为了对比这三种常用框架的易上手程度和开发速度、理解难度,我将用同一个案例,用三种框架都编写一次,实实在在的对比一下框架的区别之处,得出最终的结果。

PureMVC框架:

PureMVC优缺点:
  • 1.利用中介者,代理者,命令实现解耦,使得Model、View、Controller之间耦合性降低,提升了部分代码的重用
  • 2.View界面可以实现重用
  • 3.Model数据可以实现重用
  • 3.代码冗余量大,对于简单的功能都得创建View、Mediator、Command、Facade,Proxy,Model脚本
  • 4.操作过程比较繁琐的流程,Mediator中的代码会显得流程较为复杂难懂,除非你很熟悉PureMVC执行原理
PureMVC特点:
  • 1.通知的传递都要经过装箱和拆箱的操作
  • 2.命令/通知是以观察者模式实现,命令/通知在观察者中利用反射获取方法并执行
  • 3.没有Service(可按照MVC的构造,自行添加与网络通讯的这个模块)
  • 4.数据通过通知传递,SendNotification只有一个object类型参数,会感觉数据传输受限,可以将数据组合成一个类型/结构传递,或者是为Notification再拓展一个参数。

PureMVC Core Scripts // 核心文件

1.View.cs : IView.cs
  • 1.字典记录已注册的中介者(key是中介者名字,value是中介者接口)
  • 2.字典记录已注册的观察者(key是事件名称,value是观察者接口)
  • 3.提供注册/注销中介者和观察者的方法
  • 4.核心方法通知观察者的方法NotifyObervers
  • 5.实现View单例
  • 6.IView.cs接口规了View要实现的方法
2.Controller.cs : IController.cs
  • 字典记录已注册的命令(key是命令的名称,value是继承命令类型(实现命令接口)的类型)
  • 记录IView接口,以此来执行View中的通知,IView在构造Controller时赋值的
  • 实现Controller单例
  • 提供注册、注销、执行命令的接口
  • IController.cs接口规了View要实现的方法
3.Model.cs :IModel.cs
  • 字典记录已注册的Model代理(Proxy)(key是代理名称,value是代理类型接口)
  • 实现IModel的方法,包括注册、注销、获取代理的方法
  • 实现Model单例
  • IModel.cs接口规了View要实现的方法

在了解了核心代码的字段和方法之后,我们应该对PureMVC框架有个大概的了解,MVC三个脚本分别记录管理项目创建的所有的视图,控制器和数据模块,然后PureMVC框架利用几种典型的设计模式解除了三个模块之间的耦合,使得View和Model的代码重用性提高,下面我们简单的讲解一下涉及到的设计模式。在这里推荐一本书《大话设计模式》,不了解的同学可以去学习一下。

设计模式

代理模式

为其他对象提供一种代理以控制对这个对象的访问。
使用:在PureMVC中的使用代理模式在PureMVC中隔离了数据与其他系统的直接交互,都通过数据的代理类来进行操作,因为代理类又是继承至Notifier的所以Proxy也可以通过Notifier.IFacade访问到View和Controller,有效的隔离了数据类与其他类的耦合,使得数据类的复用性提升。这样数据类中的数据也可以由策划来用工具生成,使得开发更加的方便。

  • 外观模式
    为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个模式使得子系统更加容易使用,完美体现依赖倒置原则和迪米特法则。

使用外观模式可使子系统之间的依赖降低。

可以为旧的子系统设立一个Facade类,然后用Facade类去与新的系统交互,降低旧系统对新系统的依赖和产生复杂的关系

使用:在PureMVC中利用外观模式编写的Facade类是整个MVC框架对外的主要接口,在Facade类中记录了View、Model、COntroller并且实现了单例,它几乎拥有MVC核心类中的所有对外接口,是一个典型的高层接口。

观察者模式

是一种一对多的依赖关系,让多个观察者对象同事监听一个主题对象,这个主题对象发生变化时,会通知所有观察者对象,使他们能够自动更新自己。
使用:在PureMVC框架中利用观察者模式,在中介者类的构造函数中给中介者注册对应UI事件之后,当UI触发事件时,中介者会通过View再把通知下发给观察者,View中记录了每一个事件对应的观察者的字典,对观察者进行遍历然后执行通知中的具体事件,这里在事件通知时将类型装箱为object类型,在观察者中又通过拆箱为具体类型,利用反射构造方法实例执行,来执行通知的事件,通知的事件在构造中介者时,通过重写ListNotificationInterresets方法实现添加。

PureMVC中命令模式实现也是通过发送通知,让观察者执行通知调用Controller中的ExecuteCommand来触发的命令。

中介者模式

用一个中介对象来封装一系列的对象交互。中介者使各个对象之间不需要显示的互相引用,从而使其耦合松散,而且可以独立的改变它们之间的交互。
中介者的优缺点都很明显:优点是它减少了各个具体的类之间的耦合,使得可以独立地改变和复用各个类型。缺点是:中介者的控制会随着逻辑复杂而更加复杂,这会使得中介者承担过多的任务。

使用:在PureMVC框架中利用中介者模式有效的隔离了View层与Controller和Model层的耦合,View通过持有的数据代理,就可以有效的执行操作和数据处理。

命令模式

将一个请求封装为一个对象(即我们创建的Command对象),从而使你可用不同的请求对客户进行参数化; 对请求排队或记录请求日志,以及支持可撤销的操作。
抽象命令(Command):定义命令的接口,声明执行的方法。

具体命令(ConcreteCommand):具体命令,实现要执行的方法,它通常是“虚”的实现;通常会有接收者,并调用接收者的功能来完成命令要执行的操作。

接收者(Receiver):真正执行命令的对象。任何类都可能成为一个接收者,只要能实现命令要求实现的相应功能。

调用者(Invoker):要求命令对象执行请求,通常会持有命令对象,可以持有很多的命令对象。这个是客户端真正触发命令并要求命令执行相应操作的地方,也就是说相当于使用命令对象的入口。

客户端(Client):命令由客户端来创建,并设置命令的接收者。

使用: SimpleCommand和MarcoCommand继承ICommand接口,实现Execute方法。在代码中调用SendNotification(命令的名字),然后通知会在View.NotifyObserver()方法中通知观察者,观察者通过反射获取方法,然后执行Controller中的ExecuteCommand,ExecuteCommand中又会从字典中获取命令对应的类型,然后调用Execute执行重写的命令,实现解耦。

单例模式

单例模式是最常用的一种设计模式,单例见名知意就是一个类只有一个实例。
单例模式提供一个全局的访问点,是的程序的开发变得更加的灵活,但是单例类的增多也会导致代码过度耦合,降低复用与维护。

使用:在PureMVC中,Facade、View、Model、Controller都实现了单例模式,使得批次访问更加的方便,并加以volatile关键词(volatile多用于多线程的环境,当一个变量定义为volatile时,读取这个变量的值时候每次都是从momery里面读取而不是从cache读。这样做是为了保证读取该变量的信息都是最新的,而无论其他线程如何更新这个变量),提供互相调用的接口。

PureMVC案例演示:

案例内容:实现一个迷你餐厅游戏,有顾客、服务员、厨师、菜单、订单,实现餐厅流程的模拟

案例效果:
image.png
image.png

案例讲解:

  • 核心案例 以顾客为例
View与Mediator

ClientMediator记录ClientView变量,Mediator还记录ClientProxy,ClientProxy中记录了ClientItem数据。ClientMediator与 ClientView的挂接,我们通过一个命令来启动,在StratUpCommand中对注册Mediator,类型为ClientMediator,参数为对应的ClientView,这样Mediator(中介)持有View(视图),中介在注册时执行OnRegister方法会获取到ClientProxy的实例,通过ClientProxy给View注入数据,使得View可以显示数据。在Mediator中还会重写ListNotificationInterests给中介记录对应的通知名称,和HandleNotification方法来执行具体的通知内容。

public class ClientMediator : Mediator
{
    private ClientProxy clientProxy = null;
    public new const string NAME = "ClientMediator";

    private ClientView View
    {
        get { return (ClientView)ViewComponent; }
    }   

    public ClientMediator( ClientView view )
    {
        //注册视图中要执行的通知
        //比如点击按钮执行点菜通知
    }
    public override void OnRegister()
    {
        base.OnRegister();
        clientProxy = Facade.RetrieveProxy(ClientProxy.NAME) as ClientProxy;
        if(null == clientProxy)
            throw new Exception("获取" + ClientProxy.NAME + "代理失败");
        //更新视图内容
    }

    public override IList<string> ListNotificationInterests()
    {
        IList<string> notifications = new List<string>();
        //添加要执行的事件名称
        notifications.Add("Name");
        return notifications;
    }

    public override void HandleNotification(INotification notification)
    {
        switch(notification.Name)
        {
            case "Name":
                //todo 执行具体View方法
                break;
        }
    }
}
Model与Proxy

Model记录数据

Proxy为数据对外的代理,避免了数据直接对外,而造成Model中方法过多使得复用性降低,Model数据的获取在Proxy中可以从数据库读取,也可以从json或者Protobuf中读取。但是因为Proxy是继承至Notifier的,所以Proxy可以对外发送通知,但是它没法接收通知。比如我们从数据库抓到数据之后,就可以通过通知将数据推送给视图。

public class ClientProxy : Proxy
{
    public new const string NAME = "ClientProxy";
    public IList<ClientItem> Clients
    {
        get { return (IList<ClientItem>)base.Data; }
    }

    public ClientProxy() : base(NAME , new List<ClientItem>())
    {
        //构造ClientItem
        //或者从数据抓取
        //或者解析文件流数据
        //todo SendNotification("通知视图");
    }

    public void AddClient( ClientItem item )
    {

    }
    public void DeleteClient( ClientItem item )
    {

    }
    public void UpdateClient( ClientItem item ) 
    {

    }
}
Controller与Command

Command继承至ICommand之后一个方法Execute,在子类中重写具体的命令内容,主要用于程序启动,应用程序业务逻辑在这里实现。

Controller是所有命令的掌管者,命令的执行的入口在Contoller.ExecuteCommand方法中,是由View中NotifyObserver方法激活。

internal class StartUpCommand : SimpleCommand
{
    public override void Execute(INotification notification)
    {
        //注册代理
        //注册中介 注册中介会激活Mediator.OnRegister通过代理把数据注入视图
    }
}
  • Mini餐厅中实现了顾客与服务员的逻辑,比如拿到菜单,点菜,上菜,付款,服务员与厨师之间又实现了通知厨师做菜,厨师通知上菜等业务逻辑,这些逻辑我们都可以通过PureMVC中的通知机制来实现。

比如:

顾客通知服务员点菜:SendNotification(“通知服务员点菜”)

服务员收到通知拿着菜单给顾客:SendNotification(“上菜单”)。

  • 抽象出所有的事件流程,在EventDefines中定义名称


    image.png

所以大概分为这么几个模块去实现,每个模块都有一个View和Mediator组合,Model和Proxy组合,再统一依靠StartUpCommand与Controller启动,模块与模块之间通过Notification来实现,使得代码看起架构清晰,不杂乱。详细设计请看代码。

小结

PureMVC框架的解读今天就先讲到这里,通过上述的描述希望大家能对PureMVC框架有一个大概的了解,PureMVC框架是一种很经典的框架,在Unity之后也是较为常用的一种框架,我们从Github哪里就可以得知有多少个PureMVC语言的版本。在下一篇PureMVC解读中,我将对其中的通知模式和命令模式做一个详细的解读,去更深的了解PureMVC框架通知机制执行的原理,如果你对接口不太理解,对设计模式不太理解,或是对反射毫无概念,那你要先好好补一补这方面的姿势哟。

文章转自CSDN博主「spr1ngd」
原文链接:https://blog.csdn.net/qq_29579137/article/details/73692842

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容