作为开发人员,我们都想写出优雅的代码,可又苦于自身能力不知该如何下手,而框架的作用正在与能够让你规范的去开发。
之前写Web的时候,总被要求采用MVC架构,的确非常好用,也从来没有质疑过这种架构的好与不好。直到做游戏开发后,发现MVC架构其实很难应对游戏软件的各种需求,诸如实时战斗等。MVC特别适用于UI部分的开发,所以pureMVC我们同样也主要用在UI方面,凡是与UI有一定交互的部分,我们都可以通过MVC进行架构。
PureMVC
PureMVC框架在Unity中的应用
官方中文文档
pureMVC源码链接 选择standard版本
传统MVC在使用上,View和Controller耦合度太高,很多逻辑代码既可以写在View层又可以写在Controller层,而pureMVC引入中介者模式+消息机制来进行解耦。pureMVC仍然由Model-Controller-View组成,并且通过Facade统一进行管理。
Model层,采用代理模式,由Proxy处理数据访问,增删改查均是通过Proxy来处理,当检测到数据改变后会发送消息Notification通知View和Controller
View层,采用中介者模式,由Mediator处理数据交互,通知Controller进行逻辑处理。
Controller层,采用命令模式Command拆分逻辑,便于复用。
简单示例
以点击Button改变Text为例讲解pureMVC
GameManager.cs
// 任意文件
using UnityEngine;
// 继承mon
public class GameManager : MonoBehaviour
{void Start(){// 实例化FacadeMyFacade myFacade = new MyFacade(gameObject);}
}
MyFacede.cs
// pureMVC入口文件
using UnityEngine;
using PureMVC.Patterns.Facade;
// 继承Facede
public class MyFacade : Facade
{public MyFacade(GameObject root){// 注册Controller CommandRegisterCommand("REG_ADD", () =>{return new MyDataCommandAdd();});// 注册View MediatorRegisterMediator(new MyDataMediator(root));// 注册Model ProxyRegisterProxy(new MyDataProxy());}
}
Model层
// MyData.cs 数据文件
public class MyData
{public int value;
}
// MyDataProxy.cs 代理文件
using PureMVC.Patterns.Proxy;
// 继承Proxy
public class MyDataProxy : Proxy
{// name 必须public const string proxyName = "MYDATAPROXY";public MyData mydata = null;// 构造 实例化数据public MyDataProxy() : base(proxyName){mydata = new MyData();}// add方法,发送"MSG_ADD"消息public void AddValue(){mydata.value++;SendNotification("MSG_ADD", mydata);}public override void SendNotification(string notificationName, object body = null, string type = null){base.SendNotification(notificationName, body, type);}
}
View层
// MyDataMediator.cs 中介者文件
using UnityEngine;
using PureMVC.Patterns.Mediator;
using UnityEngine.UI;
using PureMVC.Interfaces;
// 继承Mediator
public class MyDataMediator : Mediator
{// name 必须public const string mediatorName = "Mediator";public Text textNum;public Button add;public Button sub;public MyDataMediator(GameObject root) : base (mediatorName){// 通过Find获取视图引用textNum = root.transform.Find("Text").GetComponent<Text>();add = root.transform.Find("Add").GetComponent<Button>();sub = root.transform.Find("Sub").GetComponent<Button>();// 添加事件add.onClick.AddListener(AddBtnClick);sub.onClick.AddListener(SubBtnClick);}// 接收消息列表 必须public override string[] ListNotificationInterests(){string[] list = new string[] { "MSG_ADD" };return list;}/// 消息处理 必须public override void HandleNotification(INotification notification){switch(notification.Name){case "MSG_ADD":Display(notification.Body as MyData);break;default:break;}}public void Display(MyData myData){textNum.text = myData.value.ToString();}public void AddBtnClick(){SendNotification("REG_ADD");}public override void SendNotification(string notificationName, object body = null, string type = null){base.SendNotification(notificationName, body, type);}
}
Controller层
// MyDataCommandAdd.cs 命令文件
using PureMVC.Patterns.Command;
using PureMVC.Interfaces;
// 继承SimpleCommand
public class MyDataCommandAdd : SimpleCommand
{// 重写 Executepublic override void Execute(INotification notification){// RetrieveProxy 调用add方法MyDataProxy myDataProxy = Facade.RetrieveProxy("MYDATAPROXY") as MyDataProxy;myDataProxy.AddValue();}
}
流程理解
- 当点击View界面的Button后,由Mediator开始处理,通过pureMVC提供的SendNotification方法通知Controller
- Controller接收到消息后,由相应的"REG_ADD"命令(Command)进行处理,调用Facade的RetrieveProxy方法访问数据
- Model数据由Proxy代为管理,当数据发生变化后由Proxy通过SendNotification通知View改变视图。
个人理解
pureMVC突出一个"中介"的思想,通过设计模式对MVC框架进行了解耦,Facade 外观模式、Proxy 代理模式、Mediator 中介者模式、Command 命令模式,pureMVC的消息机制通过观察者模式实现。基于这些设计,以此凸显pure的概念。