#####该文章是个人学习MVP模式的总结和实践,水平有限,谢谢指点。
前言
在游戏开发的过程中,经常会遇到修改界面风格,但是界面的功能没有发生变化的情况。如果界面和逻辑可以分开,那么改动就会减少。MVP模式可以把界面的显示,操作,和数据分离,很适合经常修改的界面。
一、MVP模式是什么?
MVP全称为Model,View,Presenter。
Model,模型,用于处理数据;
View,视图,用于显示模型中的数据;
Presenter,展示器,用于处理界面逻辑,View和Model的交互更新等。
它们之间的关系是:
View监听用户输入,发送给Presenter,Presenter根据输入执行Model中对应的数据更新操作,Model中数据变化之后通知Presenter,Presenter收到通知就从Model中获取数据更新View。
和MVC不同的是,MVP中M和V没有联系,所有的逻辑操作都是在Presenter中完成,Presenter可以监听Model的通知然后刷新View。
二、unity中实现
1.整体流程
2.具体实现
实现了一个简单的UI,里面显示角色的基本信息。
MVP接口
namespace MVP
{
/*
* Model接口
*/
public interface IUIModel
{
void Init();
}
}
namespace MVP
{
/*
* view接口
*/
public interface IUIView
{
void PreInit();
}
}
namespace MVP
{
/*
* Controller接口
*/
public interface IUIPresenter
{
void PreInit(string path);
void Show(object data);
void Hide();
void Dispose();
}
}
界面实现
namespace MVP
{
public class RoleInfoModel : IUIModel
{
public string Name;
public string Quality;
public int Hp;
public int Attack;
public int Defense;
public void Init()
{
Name = "曹操";
Quality = "极品";
Hp = 100;
Attack = 200;
Defense = 300;
}
public void Upgrade()
{
Hp += 100;
Attack += 20;
Defense += 20;
GameEvents.TriggerEvent(eEventType.RoleInfo_OnUpgrade);
}
}
}
using UnityEngine.UI;
using UnityEngine;
namespace MVP
{
public class RoleInfoView : MonoBehaviour, IUIView
{
[HideInInspector]
public Text roleName;
[HideInInspector]
public Text quality;
[HideInInspector]
public Text hp;
[HideInInspector]
public Text attack;
[HideInInspector]
public Text defense;
[HideInInspector]
public Button upgrade;
[HideInInspector]
public Button close;
[HideInInspector]
public void PreInit()
{
roleName = transform.Find("bg/name").GetComponent<Text>();
quality = transform.Find("bg/qualityDesc/quality").GetComponent<Text>();
hp = transform.Find("bg/rightInfo/hp").GetComponent<Text>();
attack = transform.Find("bg/rightInfo/attack").GetComponent<Text>();
defense = transform.Find("bg/rightInfo/defense").GetComponent<Text>();
upgrade = transform.Find("bg/upgrade").GetComponent<Button>();
close = transform.Find("bg/close").GetComponent<Button>();
}
}
}
using System;
using System.Collections.Generic;
using UnityEngine;
namespace MVP
{
public abstract class UIPresenterBase : MonoBehaviour, IUIPresenter
{
protected string uiPath;
protected abstract IUIView View
{
get;
}
public virtual void PreInit(string path)
{
uiPath = path;
}
public abstract void Show(object data);
public abstract void Hide();
public abstract void Dispose();
protected abstract void RegistEvents();
protected abstract void UnRegistEvents();
}
}
using UnityEngine;
namespace MVP
{
public class RoleInfoPresenter : UIPresenterBase
{
protected override IUIView View
{
get
{
return _view;
}
}
private RoleInfoView _view;
private RoleInfoModel model;
public override void PreInit(string path)
{
base.PreInit(path);
_view = this.transform.GetComponent<RoleInfoView>();
_view.PreInit();
model = MVPModels.GetModel(path) as RoleInfoModel;
if (model == null)
{
model = new RoleInfoModel();
model.Init();
MVPModels.RegistModel(path, model);
}
_view.upgrade.onClick.AddListener(OnClickUpgrade);
_view.close.onClick.AddListener(OnClickClose);
}
public override void Show(object data)
{
RoleInfoModel model = MVPModels.GetModel(uiPath) as RoleInfoModel;
_view.roleName.text = model.Name;
_view.quality.text = model.Quality;
_view.hp.text = model.Hp.ToString();
_view.attack.text = model.Attack.ToString();
_view.defense.text = model.Defense.ToString();
RegistEvents();
this.gameObject.SetActive(true);
}
public override void Hide()
{
this.gameObject.SetActive(false);
UnRegistEvents();
}
public override void Dispose()
{
}
private void OnClickUpgrade()
{
upgradeRole();
}
private void OnClickClose()
{
UIManager.Instance.HideUI(uiPath);
}
protected override void RegistEvents()
{
GameEvents.AddGameEvent(eEventType.RoleInfo_OnUpgrade, OnUpgraded);
}
protected override void UnRegistEvents()
{
GameEvents.RemoveGameEvent(eEventType.RoleInfo_OnUpgrade, OnUpgraded);
}
private void OnUpgraded()
{
RoleInfoModel model = MVPModels.GetModel(uiPath) as RoleInfoModel;
_view.hp.text = model.Hp.ToString();
_view.attack.text = model.Attack.ToString();
_view.defense.text = model.Defense.ToString();
}
public void upgradeRole()
{
model.Upgrade();
}
}
}
using System;
using System.Collections.Generic;
namespace MVP
{
public class MVPModels
{
private static Dictionary<string, IUIModel> uiModels = new Dictionary<string, IUIModel>();
public static void RegistModel(string type, IUIModel model)
{
if (!uiModels.ContainsKey(type))
{
uiModels.Add(type, model);
}
}
public static IUIModel GetModel(string type)
{
if (uiModels.ContainsKey(type))
{
return uiModels[type];
}
return null;
}
}
}
MVPModels中存放所有界面的Model。
代码的绑定:
GameEvents是事件管理器,可以注册和分发事件。
eEventType是事件Id的枚举。
总结
使用MVP模式制作游戏界面可以让显示和数据解耦,代码层次清晰,易于理解,MVP中View层代码因为没有什么逻辑,可以根据UI面板来生成代码,自动绑定。