【Unity 笔记】The PureMVC Framework

一、基本思想

经典的MVC框架:

  • Model(模型):管理数据
  • View(视图):管理视图
  • Controller(控制器):实现视图与数据之间传递消息

二、关于PureMVC 框架

  • Facade 管理 View、Controller、Model 三大类
  • Model 管理 Proxy,其中每个Proxy可以负责单个或多个Obj的工作
    (Obj与数据相关)
  • View 管理 Mediator,其中每个Mediator可以负责单个或多个UI的工作
    (UI与视图有关)
  • Controller 负责 Command,实现UI与Obj(即视图与数据)之间的通讯

三、核心组件 Core

3.1 数据 Mdoel

描述:存储IProxy(中介者),以及对数据的增、删、查操作。

using System.Collections.Generic;

namespace PureMVC
{
    /// <summary>
    /// 负责保存对Proxy对象的引用
    /// </summary>
    public class Model:Singleton<Model>
    {
        /// <summary>
        /// 存储 Proxy
        /// </summary>
        private Dictionary<string, IProxy> proxyMap;

        private void Awake()
        {
            proxyMap = new Dictionary<string, IProxy>();
        }

        /// <summary>
        /// 注册 Proxy
        /// </summary>
        /// <param name="proxy">数据接口内容</param>
        public void RegisterProxy(IProxy proxy)
        {
            proxyMap[proxy.ProxyName] = proxy;
        }

        /// <summary>
        /// 检索 Proxy
        /// </summary>
        /// <param name="name">数据接口 名称</param>
        public IProxy RetrieveProxy(string name)
        {
            IProxy proxy = proxyMap.ContainsKey(name) ? proxyMap[name] : null;
            return proxy;
        }

        /// <summary>
        /// 删除 Proxy
        /// </summary>
        /// <param name="name"></param>
        public void RemoveProxy(string name)
        {
            bool exist = proxyMap.ContainsKey(name) ? true : false;

            if (exist)
            {
                proxyMap.Remove(name);
            }
        }
    }
}
  • Model作为单例模式,我们希望通过全局直接访问。

3.2 视图 View

描述:存储IMediator(调节者),以及对视图个人的增、删、查操作。

using System.Collections.Generic;

namespace PureMVC
{
    /// <summary>
    /// 负责保存对Mediator的引用
    /// </summary>
    public class View: Singleton<View> 
    {
        /// <summary>
        /// 存储 Mediator
        /// </summary>
        private Dictionary<string, IMediator> mediatorMap;

        private void Awake()
        {
            mediatorMap = new Dictionary<string, IMediator>();
        }

        /// <summary>
        /// 注册 Mediator
        /// </summary>
        /// <param name="mediator"></param>
        public void RegisterMediator(IMediator mediator)
        {
            mediatorMap[mediator.MediatorName] = mediator;
        }

        /// <summary>
        /// 检索 Mediator
        /// </summary>
        /// <param name="name"></param>
        public IMediator RetrieveMediator(string name)
        {
            IMediator mediator = mediatorMap.ContainsKey(name) ? mediatorMap[name] : null;

            return mediator;
        }

        /// <summary>
        /// 删除 Mediator
        /// </summary>
        /// <param name="name"></param>
        public void RemoveMediator(string name)
        {
            bool exist = mediatorMap.ContainsKey(name) ? true : false;

            if (exist)
            {
                mediatorMap.Remove(name);
            }
        }
    }
}
  • View作为单例模式,我们希望通过全局直接访问。

3.3 消息处理中心 NotificationCenter

描述:存储IObserver(观察者),以及增、删、查基本操作。

using System.Collections.Generic;
using UnityEngine;

namespace PureMVC
{
    /// <summary>
    /// 负责保存对所有Command对象的引用
    /// </summary>
    public class NotificationCenter : Singleton<NotificationCenter>
    {
        /// <summary>
        /// 存储 Observer
        /// </summary>
        private Dictionary<string, List<IObserver>> observerMap;

        private void Awake()
        {
            observerMap = new Dictionary<string, List<IObserver>>(); 
        }

        /// <summary>
        /// 添加 Observer
        /// 注册 消息接口的信息
        /// </summary>
        /// <param name="name">消息接口 名称</param>
        /// <param name="observer">消息接口 内容</param>
        public void AddObserver(string name, IObserver observer)
        {
            if (!observerMap.ContainsKey(name))
            {
                observerMap.Add(name, new List<IObserver>());
            }
            observerMap[name].Add(observer);
        }

        /// <summary>
        /// 添加 Observer(重载)
        /// 注册 存储的监听事件信息
        /// </summary>
        /// <param name="observer">消息接口 内容</param>
        public void AddObserver(IObserver observer)
        {
            string[] list = observer.NotificationList();

            for (int i = 0; i < list.Length; i++)
            {
                AddObserver(list[i], observer);
            }
        }

        /// <summary>
        /// 删除 Observer
        /// </summary>
        /// <param name="name">消息接口 名称</param>
        /// <param name="observer">消息接口 内容</param>
        public void RemoveObserver(string name, IObserver observer)
        {
            if (!observerMap.ContainsKey(name)) return;
            if (!observerMap[name].Contains(observer)) return;

            if (observerMap[name].Count == 0)  
                observerMap.Remove(name);
            else
                observerMap[name].Remove(observer);
        }

        /// <summary>
        /// 删除 Observer(重载)
        /// </summary>
        /// <param name="observer">消息接口内容</param>
        public void RemoveObserver(IObserver observer)
        {
            string[] list = observer.NotificationList();

            for (int i = 0; i < list.Length; i++)
            {
                RemoveObserver(list[i], observer);
            }
        }

        /// <summary>
        /// 发送 消息通知
        /// </summary>
        /// <param name="name">消息接口 名称</param>
        /// <param name="data">消息接口类对象数据</param>
        public void SendNotification(string name, object data)
        {
            if (!observerMap.ContainsKey(name))
            {
                Debug.LogWarning("消息接口:" + name + "不存在");
                return;
            }

            List<IObserver> list = observerMap[name];

            for (int i = 0; i < list.Count; i++)
            {
                list[i].OnNotificationHandler(name, data);
            }
        }


        /// <summary>
        /// 打印 监听者列表
        /// </summary>
        public void PrintReaderMap()
        { 
        
        }
    }
}
  • NotificationCenter作为单例模式,我们希望通过全局直接访问。

四、关于TarenaMVC 框架

在这里插入图片描述

  • PureMVC的精简版本(将Controller精简去)
  • 适用于 中型、大型项目
  • 改良 - 将PureMVC中的View的一个消息机制强化并单独拿出作为一个消息中心

4.1 调解者接口 IMediator

namespace PureMVC
{
    /// <summary>
    /// Mediator 视图处理接口
    /// </summary>
    public interface IMediator
    {
        /// <summary>
        /// 该Mediator的命名
        /// </summary>
        string MediatorName { get; set; }
    }
}
  • 任何与视图相关的脚本需要实现接口,以告诉View自身属于视图处理,被存储于其内的MediatorMap中以便更好使用。
  • MediatorName:是命名此类调解者的名字,我们通过索引这个来查找接口对象。

4.2 中介者接口 IProxy

namespace PureMVC
{
    /// <summary>
    /// Proxy 数据处理接口
    /// </summary>
    public interface IProxy
    {
        /// <summary>
        /// 该Proxy的命名
        /// </summary>
        string ProxyName { get; set; }
    }
}
  • 任何与数据信息相关的脚本需要此接口进行实现,以告诉Model自身属于数据处理,被存储于其内的ProxyMap中以便更好使用。
  • ProxyName:是命名此类中介者的名字,我们通过索引这个来查找接口对象。

4.3 事件监听(IObserver) 与 消息发送(INotice)

namespace PureMVC
{
    /// <summary>
    /// 消息监听 接口
    /// </summary>
    public interface IObserver
    {
        /// <summary>
        /// 消息通知 接收
        /// </summary>
        /// <param name="name">消息通知 名称</param>
        /// <param name="data">消息通知 数据</param>
        void OnNotificationHandler(string name, object data);

        /// <summary>
        /// 监听 存储的消息通知列表
        /// </summary>
        /// <returns></returns>
        string[] NotificationList();
    }
}
  • 消息内容的监听器,任何来自外部的消息需要此接口进行确认与相应。
  • 适用于 视图 类 的变换时接收的指令。

namespace PureMVC
{
    /// <summary>
    /// 消息通知 接口
    /// </summary>
    public interface INotice
    {
        /// <summary>
        /// 消息通知 发送
        /// </summary>
        /// <param name="name"></param>
        /// <param name="data"></param>
        void SendNotification(string name, object data);
    }
}
  • 消息发送器:担任传出指令的角色。如控制UI界面的显隐状态,数据信息的请求等。

4.4 IModel 与 IView

  • 封装基本的对各自类型的存储XXXXMap的访问操作,如增、删、查基本操作。
  • 改 一操作:被用于脚本内修改,如proxyNamemediatorName
  • 本文中将这类操作直接添加至ModelView中。

五、封装

描述:封装MVC框架的基本操作,以便统一的引用,而非查找各自的引用方式增加难度。

5.1 入口 Facade

namespace PureMVC
{
    /// <summary>
    /// 初始化核心层Cores单例
    /// </summary>
    public class Facade : Singleton<Facade>, INotice
    {
        /// <summary>
        /// 注册 Mediator
        /// </summary>
        /// <param name="mediator"></param>
        public void RegisterMediator(IMediator mediator)
        {
            View.Instance.RegisterMediator(mediator);
        }

        /// <summary>
        /// 注册 Proxy
        /// </summary>
        /// <param name="proxy"></param>
        public void RegisterProxy(IProxy proxy)
        {
            Model.Instance.RegisterProxy(proxy);
        }

        /// <summary>
        /// 删除 Mediator
        /// </summary>
        /// <param name="name"></param>
        public void RemoveMediator(string name)
        {
            View.Instance.RemoveMediator(name);
        }

        /// <summary>
        /// 删除 Proxy
        /// </summary>
        /// <param name="name"></param>
        public void RemoveProxy(string name)
        {
            Model.Instance.RemoveProxy(name);
        }

        /// <summary>
        /// 检索 Mediator
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public IMediator RetrieveMediator(string name)
        {
            return View.Instance.RetrieveMediator(name);
        }

        /// <summary>
        /// 检索 Proxy
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public IProxy RetrieveProxy(string name)
        {
            return Model.Instance.RetrieveProxy(name);
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        public void SendNotification(string name,object data)
        {
            NotificationCenter.Instance.SendNotification(name, data);
        }
    }
}
  • Facade作为单例模式下允许全局访问。
  • 需要对各数据和视图的Map进行操作,所以封装了各自的增、删、查方法。
  • 需求发送讯息以通知数据或视图进行相应的响应,故需要INotice接口。值得注意的是,消息的发送统一交给Notification(即 消息中心)处理,而不是分开单独处理。

更多说明:
  Facade如同一个控制器,不需要其他来控制,由我们自主控制,故不需要IObserver来接收其他的消息。

5.2 中介者 Mediator

namespace PureMVC
{
    /// <summary>
    /// 负责操作具体组件,改变视图组件状态
    /// </summary>
    public class Mediator : IMediator, INotice, IObserver
    {
        /// <summary>
        /// 命名
        /// </summary>
        private const string name = "Mediator";

        /// <summary>
        /// 命名字段封装属性
        /// </summary>
        public string MediatorName { get => MediatorName; set => MediatorName = name; }

        /// <summary>
        /// 消息 发送
        /// </summary>
        public void SendNotification(string name, object data)
        {
            Facade.Instance.SendNotification(name, data);
        }

        /// <summary>
        /// 消息 接收
        /// </summary>
        /// <param name="name">消息名称</param>
        /// <param name="data">消息数据</param>
        public void OnNotificationHandler(string name, object data)
        {
            throw new System.NotImplementedException();
        }

        /// <summary>
        /// 监视 已有消息列表
        /// </summary>
        /// <returns></returns>
        public string[] NotificationList()
        {
            throw new System.NotImplementedException();
        }
    }
}
  • 即 视图层 与 数据层 之间的中介者。
  • 这是与视图相关紧密,需要IMediator,我们实现了其命名。
  • 对视图 与 对数据 的消息发送,需要INotice,值得注意的是,此处我们封装了Facade更加便利于统一发送消息。当然直接使用Notification.Instance.SendNotification(name, data)也是可行的。只不过出于以一种方式可访问全局变量的目的,请使用Facade中封装的SendNotification(name, data)方法。

5.3 调解者 Proxy

namespace PureMVC
{
    /// <summary>
    /// 处理数据
    /// </summary>
    public class Proxy : IProxy, INotice
    {
        /// <summary>
        /// 命名
        /// </summary>
        private const string name = "Proxy";

        /// <summary>
        /// 命名字段的封装属性
        /// </summary>
        public string ProxyName { get => ProxyName; set => ProxyName = name; }

        /// <summary>
        /// 消息 发送
        /// </summary>
        public void SendNotification(string name, object data)
        {
            Facade.Instance.SendNotification(name, data);
        }
    }
}
  • 即 对数据的处理。如获取SQLite数据库数据,如英雄名、技能名、CD、生命值等信息。因此需求IProxy接口,以更好在ProxyMap索引和处理。
  • 有了数据,则需要通知视图做出相应的表现,自然需要INotice接口。

更多说明:
  为什么Proxy不需要IObserver接口以接受外部消息?Proxy的职责是处理数据,如读取数据,修改数据,记录数据等。这一行为是独立进行,不需要别人告诉他"嘿!我UI变了,你得给我数据了!",而是别人"我的视图变了,我看看他提供了哪些数据索引或调整方法来使用。

六、最终框架释义图

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值