前言:
1.关于PureMVC:
MVC框架在很多项目当中拥有广泛的应用,很多时候做项目前人开坑开了一半就消失了,后人为了填补各种的坑就遭殃的不得了。嘛,程序猿大家都不喜欢像文案策划一样组织文字写东西,也不喜欢看别人留下不清不楚的文档,还不如看代码来得实在。刚开始新人看代码是看得头晕,因为这样那样的东西不一定能完全猜得透。而老人家就算有经验和阅历,也没有这么多的体力去看一个庞大而又复杂的糟糕项目。因为这种需求,Unity3D的程序猿就统一组织起来,想做一个完整规范的程序框架,而这时,PureMVC就诞生了。我个人喜欢PureMVC的原因也很简单,因为它简单粗暴,和Unity3D之间没有依赖性,加上又开源,真的遇到Bug能拿到源代码来调试也是很容易执行的。Unity3D应用商店还有一个同类产品叫uFrame Game Framework,它对Unity版本有着依赖,拖视图虽然方便,但是一旦出bug真的改得够呛的,所以不推荐使用它。下文便是使用PureMVC和Unity3D的UGUI制作一个简单的员工管理系统实例。
2.通过MVC模式在Unity项目当中应用的特别提醒:
(1)Unity3D是基于组件设计的,如果没有好的规划,组件之间会产生复杂的调用关系,导致组件之间复杂的依赖,从而破坏了整个系统结构,因此需要设计时确定组件的层次关系,确保依赖关系只存在于下层对上层。而这个是业务逻辑设计问题,PureMVC帮不了你。
(2)仅仅用上MVC,解决不了什么问题,或许解决了1%,剩下的99%就被挪到了MVC的C里,当你庆祝MVC竣工时,99%的问题在那里默默的微笑的看着你。(话说以前写PHP的CI框架时候,一堆东西扔到XxxAction.Class.php里面,发现和摆的乱七八糟的架构没区别,只是大家都习惯了这套框架的规矩,看代码找某个东西稍微好找而已,本质上还是考验基本功和对项目的熟悉程度的,23333)3.PureMVC通过4种pattern实现隔离变化:
(1)facade非常适合将UI界面对游戏数据的依赖解耦,将UI操作数据的请求封装在facade 接口里面,同时数据变化对UI的影响可以通过notification事件通知来实现,该模式应用得非常常见。
(2)command模式统一对对象的操作,将键盘输入,网络输入输出统一成command来操控游戏对象。(3)proxy维护数据,提供某块数据统一的初始化,访问和修改接口。(4)mediator没怎么用过,我们的游戏中的UI界面每次变化一般都是整体更新的,不常用局部更新。以上4中pattern请务必牢牢记住,请务必牢牢记住,请务必牢牢记住。重要的事情要说3便。4.PureMVC的流程示意图
(1)在puremvc中,model/view/controller统一是由Facade类的单件实例来统筹管理的。
(2)PureMVC的基本流程:启动PureMVC—>建立Mediator来操作视觉元素(按钮与文本框)—>点击按钮发送Notification->文本框接收Notification改变内容。(3)大致流程可理解为:通过Facade类的单件实例(即:统一的门面) 启动 puremvc环境,启动同时注册Command对象(相当于asp.net mvc中的controller),然后Command通过与之关联的facade(即前面的单件实例)来注册Mediator(中介者:用于把View与Command联系起来)。(4)当UI界面(即View)上有动静时(比如按钮点击了之类),与之关联的Mediator(中介者)会发送通知给facade,然后facade会调用command对象执行相关的处理。(即:消息响应)![](http://upload-images.jianshu.io/upload_images/442033-9830e8794e01550d.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
一.引入PureMVC的插件
1.下载PureMVC
请访问地址
安装
2.把PureMVC.DotNET.35.dll放到Plugins里面就好了。
QA
3.这里有一个很简单的基本案例可以参考一下
二.动手配置文件
1.需要完成的实例如下:
![](http://upload-images.jianshu.io/upload_images/442033-8193a9a2eb214cbd.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
2.具体实现的目标:
(1)在Scripts文件夹下,分别设置模型、视图、控制器对应的文件夹Model、View、Controller,分别放置处理数据模型的脚本、处理显示视图的脚本、处理逻辑控制的脚本。
(2)如界面,一个Unity3D和UGUI制作的简单员工管理系统,Employee Admin,其中员工界面Users显示有哪些员工在登记范围内,而New和Delete分别是添加和删除某个员工的信息。然后下面的员工信息界面User Profile则是对员工信息的一个具体编辑和修正。三.主要实现步骤
1.启动文件AppFacade.cs 作为PureMVC框架的入口文件。
1 using UnityEngine; 2 using System.Collections; 3 using PureMVC.Patterns; 4 using PureMVC.Interfaces; 5 6 //Facade模式的单例 7 public class ApplicationFacade : Facade 8 { 9 //实例化函数,保证单例模式(Singleton)运行该函数10 public new static IFacade Instance11 {12 get13 {14 if(m_instance == null)15 {16 lock(m_staticSyncRoot)17 {18 if (m_instance == null)19 {20 Debug.Log("ApplicationFacade");21 m_instance = new ApplicationFacade();22 }23 }24 }25 return m_instance;26 }27 }28 //启动PureMVC的入口函数29 public void Startup(MainUI mainUI)30 {31 Debug.Log("Startup() to SendNotification.");32 SendNotification(EventsEnum.STARTUP, mainUI);33 }34 //该类的构造器35 protected ApplicationFacade()36 {37 38 }39 //设置静态40 static ApplicationFacade()41 {42 43 }44 //初始化控制器函数45 protected override void InitializeController()46 {47 Debug.Log("InitializeController()");48 base.InitializeController();49 RegisterCommand(EventsEnum.STARTUP, typeof(StartupCommand));50 RegisterCommand(EventsEnum.DELETE_USER, typeof(DeleteUserCommand));51 }52 }
2.对PureMVC需要处理的事件用EventsEnum.cs存放
1 using UnityEngine; 2 using System.Collections; 3 4 //处理事件的枚举 5 public class EventsEnum 6 { 7 public const string STARTUP = "startup";//启动事件 8 9 public const string NEW_USER = "newUser";//新建用户10 public const string DELETE_USER = "deleteUser";//删除用户11 public const string CANCEL_SELECTED = "cancelSelected";//取消选择12 13 public const string USER_SELECTED = "userSelected";//选择用户14 public const string USER_ADDED = "userAdded";//添加用户15 public const string USER_UPDATED = "userUpdated";//更新用户16 public const string USER_DELETED = "userDeleted";//删除用户17 18 public const string ADD_ROLE = "addRole";//添加角色19 public const string ADD_ROLE_RESULT = "addRoleResult";//查询添加角色的结果20 }
3.然后在Unity的场景中创建一个MainUI.cs文件,挂在需要启动PureMVC的组件上。就可以启动了。
1 using UnityEngine; 2 using System.Collections; 3 4 //处理该UI场景的入口 5 public class MainUI : MonoBehaviour 6 { 7 public UserList userList; 8 public UserForm userForm; 9 //启动函数10 void Awake()11 {12 //启动PureMVC程序,执行StartUP()方法13 ApplicationFacade facade = ApplicationFacade.Instance as ApplicationFacade;14 facade.Startup(this);15 }16 }
4.对Controller部分进行处理
然后我们对执行逻辑的处理事件进行补充。新建一个文件夹Controller,暂时先放置StartupCommand.cs和DeleteUserCommand.cs。处理上述所说的逻辑事件
首先,处理启动事件1 using UnityEngine; 2 using System.Collections; 3 using PureMVC.Patterns; 4 using PureMVC.Interfaces; 5 6 //启动事件 7 public class StartupCommand : SimpleCommand, ICommand 8 { 9 //复写原有的Execute执行函数10 public override void Execute(INotification notification)11 {12 //注册统一的数据接口UserProxy,给其他事件处理13 Debug.Log("StartupCommand.Execute()");14 Facade.RegisterProxy(new UserProxy());15 16 //注册局部界面Mediator,给其他事件处理17 MainUI mainUI = notification.Body as MainUI;18 Facade.RegisterMediator(new UserListMediator(mainUI.userList));19 Facade.RegisterMediator(new UserFormMediator(mainUI.userForm));20 }21 }
其次,处理删除用户事件
1 using PureMVC.Patterns; 2 using PureMVC.Interfaces; 3 4 //删除用户事件 5 public class DeleteUserCommand : SimpleCommand, ICommand 6 { 7 //复写原有的Execute执行函数 8 public override void Execute(INotification notification) 9 {10 //获取要删除的对象user11 UserVO user = (UserVO)notification.Body;12 //获取处理数据操作的userProxy13 UserProxy userProxy = (UserProxy)Facade.RetrieveProxy(UserProxy.NAME);14 15 //操作数据,删除user16 userProxy.DeleteItem(user);17 //删除完毕,广播USER_DELETED进行通知18 SendNotification(EventsEnum.USER_DELETED);19 }20 }
5.对Model部分进行处理
然后是对Model模型数据的定义哈,首先要记录的信息用UserVO来表示
1 using UnityEngine; 2 using System.Collections; 3 //显示用的数据信息UserViewObject 4 public class UserVO 5 { 6 //用户名 7 public string UserName 8 { 9 get { return m_userName; }10 }11 private string m_userName = "";12 //名字13 public string FirstName14 {15 get { return m_firstName; }16 }17 private string m_firstName = "";18 //姓氏19 public string LastName20 {21 get { return m_lastName; }22 }23 private string m_lastName = "";24 //邮箱25 public string Email26 {27 get { return m_email; }28 }29 private string m_email = "";30 //密码31 public string Password32 {33 get { return m_password; }34 }35 private string m_password = "";36 //部门37 public string Department38 {39 get { return m_department; }40 }41 private string m_department = "";42 //是否合法43 public bool IsValid44 {45 get46 {47 return !string.IsNullOrEmpty(UserName) && !string.IsNullOrEmpty(Password);48 }49 }50 //合并名字51 public string GivenName52 {53 get { return LastName + ", " + FirstName; }54 }55 //构造器56 public UserVO()57 {58 }59 //构造函数60 public UserVO(string uname, string fname, string lname, string email, string password, string department)61 {62 if (uname != null) m_userName = uname;63 if (fname != null) m_firstName = fname;64 if (lname != null) m_lastName = lname;65 if (email != null) m_email = email;66 if (password != null) m_password = password;67 if (department != null) m_department = department;68 }69 }
接着对操作数据的UserProxy进行补充
1 using UnityEngine; 2 using System.Collections.Generic; 3 using PureMVC.Patterns; 4 using PureMVC.Interfaces; 5 6 //数据操作 7 public class UserProxy : Proxy, IProxy 8 { 9 public new const string NAME = "UserProxy";10 11 //返回数据操作类12 public IListUsers13 {14 get { return (IList ) base.Data; }15 }16 17 //构造函数,添加几条数据进去先18 public UserProxy():base(NAME, new List ())19 {20 Debug.Log("UserProxy()");21 //添加几条测试用的数据 22 AddItem(new UserVO("lstooge", "Larry", "Stooge", "larry@stooges.com", "ijk456", "ACCT"));23 AddItem(new UserVO("cstooge", "Curly", "Stooge", "curly@stooges.com", "xyz987", "SALES"));24 AddItem(new UserVO("mstooge", "Moe", "Stooge", "moe@stooges.com", "abc123", "PLANT"));25 AddItem(new UserVO("lzh", "abc", "def", "lzh@stooges.com", "abc123", "IT"));26 }27 28 //添加数据的方法29 public void AddItem(UserVO user)30 {31 Users.Add(user);32 }33 34 //更新数据的方法35 public void UpdateItem(UserVO user)36 {37 for (int i = 0; i < Users.Count; i++)38 {39 if (Users[i].UserName.Equals(user.UserName))40 {41 Users[i] = user;42 break;43 }44 }45 }46 47 //删除数据的方法48 public void DeleteItem(UserVO user)49 {50 for (int i = 0; i < Users.Count; i++)51 {52 if (Users[i].UserName.Equals(user.UserName))53 {54 Users.RemoveAt(i);55 break;56 }57 }58 }59 }
6.接下来对VIew部分进行实现
显示用户界面列表的UserList和填写用户具体信息的UserForm
列表单条数据部分1 using UnityEngine; 2 using UnityEngine.UI; 3 using System.Collections; 4 5 //UserList列表当中单条数据信息 6 public class UserList_Item : MonoBehaviour 7 { 8 //定义UI组件 9 public Text txt_userName;//用户名文本框10 public Text txt_firstName;//名字文本框11 public Text txt_lastName;//姓氏文本框12 public Text txt_email;//邮件文本框13 public Text txt_department;//部门文本框14 15 //定义User信息类16 public UserVO userData;17 18 //更新User类19 public void UpdateData(UserVO data)20 {21 //获取需要更改的User信息22 this.userData = data;23 24 //更改UI的文字信息25 txt_userName.text = data.UserName;26 txt_firstName.text = data.FirstName;27 txt_lastName.text = data.LastName;28 txt_email.text = data.Email;29 txt_department.text = data.Department;30 }31 }
用户列表部分
using UnityEngine;using UnityEngine.UI;using System.Collections;using System.Collections.Generic;//UserList用户界面列表部分public class UserList : MonoBehaviour{ //定义UI组件 public Text txt_userCount;//用户列表文本框 public UGUI_MyToggleGroup myToggleGroup;//用户列表滑动条 public Button btn_New;//新建按钮 public Button btn_Delete;//删除按钮 public UserList_Item itemPrefab;//单个列表文件的预置体 ListitemList = new List ();//临时存列表 //定义事件操作 public System.Action NewUser;//添加用户事件 public System.Action DeleteUser;//删除用户事件 public System.Action SelectUser;//选择用户事件 //定义数据 public UserVO SelectedUserData;//列表中选择好的用户 private IList m_currentUsers;//当前选择的用户 //开始函数 void Start () { itemPrefab.gameObject.SetActive(false); myToggleGroup.onToggleChange.AddListener(onSelectUserItem); btn_New.onClick.AddListener(onClick_btn_New); btn_Delete.onClick.AddListener(onClick_btn_Delete); UpdateButtons(); } //加载用户 public void LoadUsers(IList list) { m_currentUsers = list; RefreshUI(list); } //点击新建 void onClick_btn_New() { if (NewUser != null) NewUser(); } //点击删除 void onClick_btn_Delete() { if (DeleteUser != null) DeleteUser(); } //选择物体 void onSelectUserItem(Toggle itemToggle) { if (itemToggle == null) { return; } UserList_Item item = itemToggle.GetComponent (); this.SelectedUserData = item.userData; UpdateButtons(); if (SelectUser != null) SelectUser(); } //取消选择 public void Deselect() { myToggleGroup.toggleGroup.SetAllTogglesOff(); this.SelectedUserData = null; UpdateButtons(); } //刷新UI void RefreshUI(IList datas) { ClearItems(); foreach (var data in datas) { UserList_Item item = CreateItem(); item.UpdateData(data); itemList.Add(item); } txt_userCount.text = datas.Count.ToString(); } //新建列表项目 UserList_Item CreateItem() { UserList_Item item = GameObject.Instantiate (itemPrefab); item.transform.SetParent(itemPrefab.transform.parent); item.gameObject.SetActive(true); item.transform.localScale = Vector3.one; item.transform.localPosition = Vector3.zero; return item; } //清空列表 void ClearItems() { foreach(var item in itemList) { Destroy(item.gameObject); } itemList.Clear(); } //更新按钮 private void UpdateButtons() { btn_Delete.interactable = (SelectedUserData != null); }}
用户个人信息部分
1 using UnityEngine; 2 using UnityEngine.UI; 3 using System.Collections; 4 using UnityEngine.EventSystems; 5 6 //用户个人信息表单模式?编辑:新增 7 public enum UserFormMode 8 { 9 ADD, 10 EDIT, 11 } 12 //用户个人信息表单 13 public class UserForm : MonoBehaviour 14 { 15 //UI项的定义 16 public InputField txt_firstName; 17 public InputField txt_lastName; 18 public InputField txt_email; 19 public InputField txt_userName; 20 public InputField txt_password; 21 public InputField txt_confirmPassword; 22 public InputField txt_department; 23 public Button btn_updateUser; 24 public Button btn_cancel; 25 26 //其他 27 public System.Action AddUser; 28 public System.Action UpdateUser; 29 public System.Action CancelUser; 30 31 //用户信息获取 32 public UserVO User 33 { 34 get { return m_user; } 35 } 36 private UserVO m_user; 37 38 //用户信息表单 39 public UserFormMode Mode 40 { 41 get { return m_mode; } 42 } 43 private UserFormMode m_mode = UserFormMode.ADD; 44 45 //开始 46 void Start () 47 { 48 //设置UI 49 btn_updateUser.onClick.AddListener(btn_updateUser_Click); 50 btn_cancel.onClick.AddListener(btn_cancel_Click); 51 52 txt_userName.onValueChange.AddListener(InputField_onValueChange); 53 txt_password.onValueChange.AddListener(InputField_onValueChange); 54 txt_confirmPassword.onValueChange.AddListener(InputField_onValueChange); 55 56 UpdateButtons(); 57 } 58 59 //显示当前用户信息 60 public void ShowUser(UserVO user, UserFormMode mode) 61 { 62 m_mode = mode; 63 if (user == null) 64 { 65 ClearForm(); 66 } 67 else 68 { 69 m_user = user; 70 txt_firstName.text = user.FirstName; 71 txt_lastName.text = user.LastName; 72 txt_email.text = user.Email; 73 txt_userName.text = user.UserName; 74 txt_password.text = txt_confirmPassword.text = user != null ? user.Password : ""; 75 txt_department.text = user.Department; 76 //txt_firstName.ActivateInputField(); 77 EventSystem.current.SetSelectedGameObject(txt_firstName.gameObject); 78 //txt_firstName.MoveTextEnd(false); 79 txt_firstName.caretPosition = txt_firstName.text.Length - 1; 80 UpdateButtons(); 81 } 82 } 83 84 //更新按钮 85 private void UpdateButtons() 86 { 87 if (btn_updateUser != null) 88 { 89 btn_updateUser.interactable = (txt_firstName.text.Length > 0 && txt_password.text.Length > 0 && txt_password.text.Equals(txt_confirmPassword.text)); 90 } 91 } 92 93 //清空表单 94 public void ClearForm() 95 { 96 m_user = null; 97 txt_firstName.text = txt_lastName.text = txt_email.text = txt_userName.text = ""; 98 txt_password.text = txt_confirmPassword.text = ""; 99 txt_department.text = "";100 UpdateButtons();101 }102 103 //更新用户信息104 void btn_updateUser_Click()105 {106 m_user = new UserVO(107 txt_userName.text, txt_firstName.text, 108 txt_lastName.text, txt_email.text, 109 txt_password.text, txt_department.text);110 111 if (m_user.IsValid)112 {113 if (m_mode == UserFormMode.ADD)114 {115 if (AddUser != null) AddUser();116 }117 else118 {119 if (UpdateUser != null) UpdateUser();120 }121 }122 }123 124 //取消信息125 void btn_cancel_Click()126 {127 if (CancelUser != null) CancelUser();128 }129 130 //输入131 void InputField_onValueChange(string value)132 {133 UpdateButtons();134 }135 }
最后,对局部更新UI的行为进行完善Mediator
1 using UnityEngine; 2 using System.Collections; 3 using PureMVC.Patterns; 4 using PureMVC.Interfaces; 5 using System.Collections.Generic; 6 //更新UserList部分 7 public class UserListMediator : Mediator, IMediator 8 { 9 private UserProxy userProxy;10 11 public new const string NAME = "UserListMediator";12 13 private UserList View14 {15 get { return (UserList)ViewComponent; }16 }17 18 public UserListMediator(UserList userList)19 : base(NAME, userList)20 {21 Debug.Log("UserListMediator()");22 userList.NewUser += userList_NewUser;23 userList.DeleteUser += userList_DeleteUser;24 userList.SelectUser += userList_SelectUser;25 }26 27 public override void OnRegister()28 {29 Debug.Log("UserListMediator.OnRegister()");30 base.OnRegister();31 userProxy = Facade.RetrieveProxy(UserProxy.NAME) as UserProxy;32 View.LoadUsers(userProxy.Users);33 }34 35 void userList_NewUser()36 {37 UserVO user = new UserVO();38 SendNotification(EventsEnum.NEW_USER, user);39 }40 41 void userList_DeleteUser()42 {43 SendNotification(EventsEnum.DELETE_USER, View.SelectedUserData);44 }45 46 void userList_SelectUser()47 {48 SendNotification(EventsEnum.USER_SELECTED, View.SelectedUserData);49 }50 51 public override IListListNotificationInterests()52 {53 IList list = new List ();54 list.Add(EventsEnum.USER_DELETED);55 list.Add(EventsEnum.CANCEL_SELECTED);56 list.Add(EventsEnum.USER_ADDED);57 list.Add(EventsEnum.USER_UPDATED);58 return list;59 }60 61 public override void HandleNotification(INotification notification)62 {63 switch(notification.Name)64 {65 case EventsEnum.USER_DELETED:66 View.Deselect();67 View.LoadUsers(userProxy.Users);68 break;69 case EventsEnum.CANCEL_SELECTED:70 View.Deselect();71 break;72 case EventsEnum.USER_ADDED:73 View.Deselect();74 View.LoadUsers(userProxy.Users);75 break;76 case EventsEnum.USER_UPDATED:77 View.Deselect();78 View.LoadUsers(userProxy.Users);79 break;80 }81 }82 }
1 using UnityEngine; 2 using System.Collections; 3 using PureMVC.Patterns; 4 using PureMVC.Interfaces; 5 using System.Collections.Generic; 6 //更新UserForm部分 7 public class UserFormMediator : Mediator, IMediator 8 { 9 private UserProxy userProxy;10 11 public new const string NAME = "UserFormMediator";12 13 private UserForm View14 {15 get { return (UserForm)ViewComponent; }16 }17 18 public UserFormMediator(UserForm viewComponent)19 : base(NAME, viewComponent)20 {21 Debug.Log("UserFormMediator()");22 23 View.AddUser += UserForm_AddUser;24 View.UpdateUser += UserForm_UpdateUser;25 View.CancelUser += UserForm_CancelUser;26 }27 28 public override void OnRegister()29 {30 base.OnRegister();31 userProxy = Facade.RetrieveProxy(UserProxy.NAME) as UserProxy;32 }33 34 void UserForm_AddUser()35 {36 UserVO user = View.User;37 userProxy.AddItem(user);38 SendNotification(EventsEnum.USER_ADDED, user);39 View.ClearForm();40 }41 42 void UserForm_UpdateUser()43 {44 UserVO user = View.User;45 userProxy.UpdateItem(user);46 SendNotification(EventsEnum.USER_UPDATED, user);47 View.ClearForm();48 }49 50 void UserForm_CancelUser()51 {52 SendNotification(EventsEnum.CANCEL_SELECTED);53 View.ClearForm();54 }55 56 public override IListListNotificationInterests()57 {58 IList list = new List ();59 list.Add(EventsEnum.NEW_USER);60 list.Add(EventsEnum.USER_DELETED);61 list.Add(EventsEnum.USER_SELECTED);62 return list;63 }64 65 public override void HandleNotification(INotification note)66 {67 UserVO user;68 switch (note.Name)69 {70 case EventsEnum.NEW_USER:71 user = (UserVO)note.Body;72 View.ShowUser(user, UserFormMode.ADD);73 break;74 75 case EventsEnum.USER_DELETED:76 View.ClearForm();77 break;78 79 case EventsEnum.USER_SELECTED:80 user = (UserVO)note.Body;81 View.ShowUser(user, UserFormMode.EDIT);82 break;83 84 }85 }86 }
补充,UI的选择部分
1 using UnityEngine; 2 using UnityEngine.UI; 3 using System.Collections; 4 5 [RequireComponent(typeof(Toggle))] 6 public class UGUI_MyToggle : MonoBehaviour 7 { 8 [SerializeField]Toggle toggle; 9 [SerializeField]UGUI_MyToggleGroup myToggleGroup;10 11 void Start()12 {13 if (toggle == null) toggle = this.GetComponent();14 if (myToggleGroup == null) myToggleGroup = toggle.group.GetComponent ();15 16 toggle.onValueChanged.AddListener(onToggle);17 }18 19 void onToggle(bool value)20 {21 if(value)22 {23 myToggleGroup.ChangeToggle(toggle);24 }25 }26 }
原文地址: