【Unity】使用事件管理器的方式解耦MVP

前情提要:【Unity】MVP框架的使用例子

        在上一篇文章的代码实现中,我们会发现,Model层兼顾了:为Presenter层提供响应数据更新的事件,添加事件的方法和移除事件的方法等。

        这显然不是我们需要的,作为数据层我们更希望它只是处理数据相关,对事件的过多操作也提升了Model层与Presenter层的耦合度,因此我们在他们之间添加如下的事件管理器EventManager.cs:

using System.Collections.Generic;
using UnityEngine.Events;

public interface IEvent{}

public class EventClas<T> : IEvent
{
    public UnityAction<T> actions;

    public EventClas(UnityAction<T> action)
    {
        actions += action;
    }
}

public class EventClas : IEvent
{
    public UnityAction actions;

    public EventClas(UnityAction action)
    {
        actions += action;
    }
}

/// <summary>
/// 事件中心
/// </summary>
public class EventManager : BaseManager<EventManager>
{   
    //事件缓存器
    //key表示事件名称
    //value为事件对象
    private Dictionary<string, IEvent> eventDic = new();

    /// <summary>
    /// 添加带参数的事件
    /// </summary>
    /// <typeparam name="T">事件参数类型</typeparam>
    /// <param name="name">事件名称</param>
    /// <param name="action">传入的事件</param>
    public void AddEventListener<T>(string name, UnityAction<T> action)
    {   
        //若已有该事件的名称,则将传入的事件添加至该事件内
        if(eventDic.ContainsKey(name))
        {
            (eventDic[name] as EventClas<T>).actions += action;
        }
        //若没有,则创建,并将其放入字典中
        else
        {
            eventDic.Add(name, new EventClas<T>(action));
        }
    }

    /// <summary>
    /// 监听不需要参数传递的事件
    /// </summary>
    /// <param name="name">事件名称</param>
    /// <param name="action">传入的事件</param>
    public void AddEventListener(string name, UnityAction action)
    {
        //若已有该事件的名称,则将传入的事件添加至该事件内
        if (eventDic.ContainsKey(name))
        {
            (eventDic[name] as EventClas).actions += action;
        }
        //若没有,则创建,并将其放入字典中
        else
        {
            eventDic.Add(name, new EventClas(action));
        }
    }

    /// <summary>
    /// 移除带参数的事件
    /// </summary>
    /// <typeparam name="T">事件的参数类型</typeparam>
    /// <param name="name">事件名称</param>
    public void RemoveEventListener<T>(string name, UnityAction<T> action)
    {
        if(eventDic.ContainsKey(name))
            (eventDic[name] as EventClas<T>).actions -= action;
    }

    /// <summary>
    /// 移除不带参数的事件
    /// </summary>
    /// <param name="name">事件名称</param>
    /// <param name="action">事件</param>
    public void RemoveEventListener(string name, UnityAction action)
    {
        if(eventDic.ContainsKey(name))
            (eventDic[name] as EventClas).actions -= action;
    }

    /// <summary>
    /// 事件触发(带参数版)
    /// </summary>
    /// <typeparam name="T">事件参数类型</typeparam>
    /// <param name="name">事件对应名称</param>
    /// <param name="info">事件参数</param>
    public void EventTrigger<T>(string name, T info)
    {
        if(eventDic.ContainsKey(name))
        {
            if ((eventDic[name] as EventClas<T>).actions != null)
            {
                (eventDic[name] as EventClas<T>).actions.Invoke(info);
            }
        }
    }

    /// <summary>
    /// 事件触发(不带参数版)
    /// </summary>
    /// <param name="name">事件对应名称 </param>
    public void EventTrigger(string name)
    {
        if(eventDic.ContainsKey(name))
        {
            if ((eventDic[name] as EventClas).actions != null)
            {
                (eventDic[name] as EventClas).actions.Invoke();
            }
        }
    }

    /// <summary>
    /// 清空事件缓存
    /// </summary>
    public void ClearEventDic()
    {
        eventDic.Clear();
    }
}

并且在上一篇帖子的基础上,对RolePresenter_MVP.cs进行修改为(红色为修改部分):

using UnityEngine;

public class RolePresenter_MVP : MonoBehaviour
{
    //自己的单例(作为系统访问MVC的入口)
    private static RolePresenter_MVP instance;
    public static RolePresenter_MVP Instance
    {
        get
        {
            return instance;
        }
    }

    private RoleView_MVP roleView;//对应的视图层
    private RoleModel_MVP roleModel => RoleModel_MVP.Instance;

    // Start is called before the first frame update
    void Start()
    {
        if (roleView == null)
        {
            //1.获取相关引用
            //获取Panel
            //获取组件
            roleView = this.GetComponent<RoleView_MVP>();
            instance = this.GetComponent<RolePresenter_MVP>();

            //2.初始化
            roleModel.InitData();
            UpdateEvent(roleModel);
            //roleView.UpdateUIInfo(playerModel);

            //3.绑定相应逻辑
            //View层绑定业务
            roleView.hurtButton.onClick.AddListener(HurtBtnMethod);

            //Model层绑定更新事件
            //RoleModel_MVP.Instance.AddUpdateEvent(UpdateEvent);
            EventManager.Instance.AddEventListener<RoleModel_MVP>("UpdateRoleInfo", UpdateEvent);

        }
    }

    /// <summary>
    /// 受伤按钮绑定的方法
    /// </summary>
    private void HurtBtnMethod()
    {
        //受伤
        RoleModel_MVP.Instance.UpdateData();
    }

    private void OnDestroy()
    {
        //1.移除业务
        //2.销毁对象
        //3.置空
        if (roleView != null)
        {
            roleView.hurtButton.onClick.RemoveListener(HurtBtnMethod);
            Destroy(roleView);
            roleView = null;
        }

        //移除事件
        //RoleModel_MVP.Instance.RemoveUpdateEvent(UpdateEvent);
        EventManager.Instance.RemoveEventListener<RoleModel_MVP>("UpdateRoleInfo", UpdateEvent);
    }

    /// <summary>
    /// 更新数据
    /// </summary>
    /// <param name="roleModel"></param>
    private void UpdateEvent(RoleModel_MVP roleModel)
    {
        roleView.health_Text.text = "当前生命值:" + roleModel.Health.ToString();
    }
}


对RoleModel_MVP.cs修改为:

using UnityEngine;

public class RoleModel_MVP
{
    //自身的单例,让数据在整个游戏中只存在一份
    private static RoleModel_MVP instance = null;
    public static RoleModel_MVP Instance
    {
        get
        {
            if (instance == null)
                instance = new RoleModel_MVP();
            return instance;
        }
    }

    //数据
    private int health;//生命值
    public int Health
    {
        get
        {
            return health;
        }
    }

    反馈给Controller的更新事件
    //public UnityAction<RoleModel_MVP> updateModelEvent = null;

    //1.初始化数据
    public void InitData()
    {
        PlayerPrefs.SetInt("Health", 100);
        health = PlayerPrefs.GetInt("Health");//初始化生命值,若在PlayerPrefs中没有这个属性则创建它,并将其的数值设置为100
    }

    //2.更新数据,假定更新一次减少10的生命值
    public void UpdateData()
    {
        health -= 10;

        //保存数据
        SaveData();
    }

    //3.保存数据
    public void SaveData()
    {
        PlayerPrefs.SetInt("Health", health);

        触发更新事件
        //UpdateDataInvoke();

        EventManager.Instance.EventTrigger<RoleModel_MVP>("UpdateRoleInfo", this);
    }

    4.更新后触发的事件

    / <summary>
    / 添加事件的方法
    / </summary>
    / <param name="action"></param>
    //public void AddUpdateEvent(UnityAction<RoleModel_MVP> action)
    //{
    //    if (action != null)
    //        updateModelEvent += action;
    //}

    / <summary>
    / 移除事件的方法
    / </summary>
    / <param name="action"></param>
    //public void RemoveUpdateEvent(UnityAction<RoleModel_MVP> action)
    //{
    //    if (action != null)
    //        updateModelEvent -= action;
    //}

    / <summary>
    / 更新时的操作
    / </summary>
    //private void UpdateDataInvoke()
    //{
    //    if (updateModelEvent != null)
    //    {
    //        updateModelEvent?.Invoke(this);
    //    }
    //}
}

        可以发现,我们通过了事件管理器,将Model层中的添加和移除事件,以及定义事件的代码都移到了事件管理器中,使得Model层成为了一个专注地去实现数据处理模块。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值