前情提要:【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层成为了一个专注地去实现数据处理模块。