<碼字不易,希望大家點點關注支持一下>
PureMVC框架解讀
我們先講解一下簡單事件系統(tǒng)和PureMVC中的命令/通知系統(tǒng)做個比較送讲。
1.簡單事件系統(tǒng)
<事件系統(tǒng)是委托的典型用法死宣,C#委托包含Action、delegate碴开、Func毅该、predicate幾種類型,具體的用法可以去百度查閱一下其他資料潦牛,這里我們先簡單講解一下事件系統(tǒng)眶掌。事件系統(tǒng)在Unity中可以用來解耦視圖與模型,使得視圖和模型重用性都有所提升。Unity WIKI這里有很多變種的事件系統(tǒng)巴碗。>
1.1 什么是事件系統(tǒng)
簡單講就是利用字典記錄方法,執(zhí)行事件系統(tǒng)就是調(diào)用已經(jīng)記錄的方法朴爬。
1.字典記錄事件集合
2.執(zhí)行事件的接口
3.注冊事件的接口
4.注銷事件的接口
5.清空事件的接口
6.接口通常會有幾個重載方法,實現(xiàn)不同的參數(shù)數(shù)量
1.2 事件系統(tǒng)代碼
以下是一個簡易事件系統(tǒng)的模板:
public class EventSystem
{
//事件字典
private static readonly Dictionary<string , Delegate> Events = new Dictionary<string, Delegate>();
//執(zhí)行事件的重載方法
public static void Invoke(string eventName)
{
foreach (Delegate @delegate in invoke(eventName))
@delegate.DynamicInvoke();
}
public static void Invoke<T>(string eventName,T argt ){}
//執(zhí)行事件異常檢查
private static Delegate[] invoke( string eventName )
{
if (!Events.ContainsKey(eventName))
UnityEngine.Debug.LogError(string.Format("Can not get the {0} event!",eventName));
Delegate @delegate = Events[eventName];
return @delegate.GetInvocationList();
}
//注冊事件的重載方法
public static void Register( string eventName, Action action )
{
register(eventName);
Events[eventName] = (Action)Events[eventName] + action;
}
public static void Register<T>( string eventName , Action<T> action ){}
//注冊事件
private static void register( string eventName )
{
if (!Events.ContainsKey(eventName))
Events.Add(eventName, null);
}
//注銷事件的重載方法
public static void UnRegister( string eventName , Action action )
{
register(eventName);
Events[eventName] = (Action)Events[eventName] - action;
}
//清楚事件的重載方法
public static void Clear( string eventName )
{
if (Events.ContainsKey(eventName))
Events[eventName] = null;
}
}
1.3 事件系統(tǒng)案例
結合一個小的案例看一下簡單的事件系統(tǒng)的使用:
internal class TestClass : MonoBehaviour
{
public const string EVENT_NAME = "EventName";
private void Awake()
{
TestEvent test = new TestEvent();
//注冊事件
EventSystem.Register(EVENT_NAME,test.Invoke);
}
}
internal class TestEvent
{
public void Invoke()
{
Debug.Log("Invoke");
}
}
internal class TestInvoker : MonoBehaviour
{
public const string EVENT_NAME = "EventName";
public void Start()
{
//執(zhí)行事件橡淆,即可執(zhí)行以及注冊對應的事件
SpringFramework.Event.EventSystem.Invoke(EVENT_NAME);
}
}
通過以上簡述大家應該對簡易事件系統(tǒng)有個了解召噩,接下里我們看看PureMVC中的命令/通知系統(tǒng)母赵,功能和簡易事件系統(tǒng)一樣實現(xiàn)部分代碼之間的解耦,讓方法調(diào)用更加的便捷具滴。
2.PureMVC通知系統(tǒng)
2.1 PureMVC
通知系統(tǒng)與簡易事件系統(tǒng)的區(qū)別
業(yè)務拆分更加細致凹嘲,通知內(nèi)容(Notificatoin:INotification),通知發(fā)送者(Notifer:INotifer)构韵,通知執(zhí)行者(Observer:IObserver)全部都拆分為具體的類型周蹭,使得整個系統(tǒng)的拓展性更強。
Notification作為單獨類型可自由定義通知內(nèi)容疲恢,拓展方便簡單凶朗,簡易事件系統(tǒng)拓展會受到參數(shù)數(shù)量限制,導致拓展復雜显拳。
簡易事件系統(tǒng)參數(shù)是通過泛型方法來定義的棚愤,但是PureMVC中將參數(shù)裝箱為object類型,然后在執(zhí)行時拆箱為對應類型萎攒,雖然裝箱拆箱消耗了一定的性能遇八,但是使得參數(shù)傳遞變得更加簡單,方便耍休。
2.2PureMVC通知系統(tǒng)代碼分析
通知系統(tǒng)大概拆分為通知發(fā)送者(Notifer),通知內(nèi)容(Notification),通知觀察者/執(zhí)行者(Observer)
2.2.1 PureMVC通知系統(tǒng)核心代碼分析
- Notifer:INotifer 發(fā)送通知的方法
public interface INotifier
{
//發(fā)送通知的重載方法
void SendNotification(string notificationName);
void SendNotification(string notificationName, object body);
void SendNotification(string notificationName, object body, string type);
}
public class Notifier : INotifier
{
//保存Facade的實例刃永,通知通過外觀Facade通知給View(外觀者保存了MVC三個模塊的實例),View記錄了所有的觀察者,然后遍歷觀察者找到對應的觀察者羊精,通知觀察者執(zhí)行通知
private IFacade m_facade = PureMVC.Patterns.Facade.Instance;
public void SendNotification(string notificationName)
{
this.m_facade.SendNotification(notificationName);
}
public void SendNotification(string notificationName, object body)
{
this.m_facade.SendNotification(notificationName, body);
}
public void SendNotification(string notificationName, object body, string type)
{
this.m_facade.SendNotification(notificationName, body, type);
}
protected IFacade Facade
{
get
{
return this.m_facade;
}
}
}
- Notification:INotification 通知的具體內(nèi)容
public interface INotification
{
//重寫通知ToString,用于調(diào)試輸出
string ToString();
//通知事件
object Body { get; set; }
//通知名稱
string Name { get; }
//通知類型
string Type { get; set; }
}
//Notification只是實現(xiàn)了接口中的內(nèi)容
public class Notification : INotification
{
private object m_body;
private string m_name;
private string m_type;
public Notification(string name) : this(name, null, null){}
public Notification(string name, object body) : this(name, body, null){}
public Notification(string name, object body, string type)
{
this.m_name = name;
this.m_body = body;
this.m_type = type;
}
public override string ToString()
{
return ((("Notification Name: " + this.Name) + "\nBody:" + ((this.Body == null) ? "null" : this.Body.ToString())) + "\nType:" + ((this.Type == null) ? "null" : this.Type));
}
public object Body
{
get
{
return this.m_body;
}
set
{
this.m_body = value;
}
}
public string Name
{
get
{
return this.m_name;
}
}
public string Type
{
get
{
return this.m_type;
}
set
{
this.m_type = value;
}
}
}
- Observer : IObserver 觀察者/執(zhí)行者斯够,根據(jù)通知內(nèi)容反射得到中介者和命令的方法,然后傳參數(shù)執(zhí)行喧锦。
public interface IObserver
{
//對比NotifyContext
bool CompareNotifyContext(object obj);
//通知觀察者
void NotifyObserver(INotification notification);
//記錄是Mediator或Command
object NotifyContext { set; }
//通知方法
string NotifyMethod { set; }
}
public class Observer : IObserver
{
//...其他的字段和方法
public void NotifyObserver(INotification notification)
{
object notifyContext;
lock (this.m_syncRoot)
{
notifyContext = this.NotifyContext;
}
//利用反射獲取方法然后執(zhí)行
Type type = notifyContext.GetType();
//這里設置忽略字母的大小寫|公共成員|實例成員
BindingFlags bindingAttr = BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase;
//根據(jù)設置的中介者的名字或者是命令的名字執(zhí)行對應的方法
//如果notifyContext是中介者(Mediator)方法名是HandleNotification
//notifyContext是命令方法名是ExecuteCommand
//HandleNotification和ExecuteCommand在注冊中介者和命令時構造的Observer的名字為notifyContext或HandleNotification
MethodInfo method = type.GetMethod(this.NotifyMethod, bindingAttr);
method.Invoke(notifyContext , new object[] { notification });
}
}
2.2.2 PureMVC通知系統(tǒng)與MVC結合代碼分析
- 注冊
<因為觀察者/執(zhí)行者是在注冊中介者或者是命令的時候構造并存入字典的读规,在View.RegisterMediator方法中構造觀察者并寫入字典,命令的注冊時在Controller中執(zhí)行的燃少,Controller又通過View的實例調(diào)用View中的RegisterObserver注冊命令的觀察者/執(zhí)行者>
public class View : IView
{
protected IDictionary<string, IMediator> m_mediatorMap = new Dictionary<string, IMediator>();
//觀察者字典
protected IDictionary<string, IList<IObserver>> m_observerMap = new Dictionary<string, IList<IObserver>>();
public virtual void RegisterMediator(IMediator mediator)
{
lock (this.m_syncRoot)
{
if (this.m_mediatorMap.ContainsKey(mediator.MediatorName))
{
return;
}
this.m_mediatorMap[mediator.MediatorName] = mediator;
//獲取中介者的通知列表
IList<string> list = mediator.ListNotificationInterests();
if (list.Count > 0)
{
IObserver observer = new Observer("handleNotification", mediator);
for (int i = 0; i < list.Count; i++)
{
//將通知名注冊給觀察者
this.RegisterObserver(list[i].ToString(), observer);
}
}
}
mediator.OnRegister();
}
public virtual void RegisterObserver(string notificationName, IObserver observer)
{
lock (this.m_syncRoot)
{
if (!this.m_observerMap.ContainsKey(notificationName))
{
//字典key存儲通知名稱 value存儲觀察者
this.m_observerMap[notificationName] = new List<IObserver>();
}
this.m_observerMap[notificationName].Add(observer);
}
}
}
//命令的注冊
public class Controller : IController
{
// 記錄命令的類型
protected IDictionary<string, Type> m_commandMap = new Dictionary<string, Type>();
protected IView m_view;
public virtual void RegisterCommand(string notificationName, Type commandType)
{
lock (this.m_syncRoot)
{
if (!this.m_commandMap.ContainsKey(notificationName))
{
this.m_view.RegisterObserver(notificationName, new Observer("executeCommand", this));
}
this.m_commandMap[notificationName] = commandType;
}
}
}
- 執(zhí)行
<通過Notifer(執(zhí)行者)我們知道通知的發(fā)送是通過Facade.m_view.NotifyObservers()方法發(fā)出的>
public class View : IView
{
public virtual void NotifyObservers(INotification notification)
{
IList<IObserver> list = null;
lock (this.m_syncRoot)
{
if (this.m_observerMap.ContainsKey(notification.Name))
{
IList<IObserver> collection = this.m_observerMap[notification.Name];
//獲取到通知已經(jīng)注冊的所有觀察者
list = new List<IObserver>(collection);
}
}
if (list != null)
{
for (int i = 0; i < list.Count; i++)
{
//遍歷觀察者并執(zhí)行觀察者中的方法束亏,通過反射獲取方法執(zhí)行HandleNotification或者ExecuteCommnd
//ExecuteCommand是Controller中的方法,它會遍歷所有的命令類型找到對應的命令然后執(zhí)行Execute方法
list[i].NotifyObserver(notification);
}
}
}
}
<執(zhí)行的方法類似以下:>
public class ClientMediator : Mediator
{
public override void HandleNotification(INotification notification)
{
switch (notification.Name)
{
case OrderSystemEvent.CALL_WAITER:
ClientItem client = notification.Body as ClientItem;
if(null == client)
throw new Exception("對應桌號顧客不存在阵具,請核對碍遍!");
Debug.Log(client.id + " 號桌顧客呼叫服務員 , 索要菜單 ");
break;
case OrderSystemEvent.ORDER:
Order order1 = notification.Body as Order;
if(null == order1)
throw new Exception("order1 is null ,please check it!");
order1.client.state++;
View.UpdateState(order1.client);
break;
case OrderSystemEvent.PAY:
Order finishOrder = notification.Body as Order;
if ( null == finishOrder )
throw new Exception("finishOrder is null ,please check it!");
finishOrder.client.state++;
View.UpdateState(finishOrder.client);
SendNotification(OrderSystemEvent.GET_PAY, finishOrder);
break;
}
}
}
internal class StartUpCommand : SimpleCommand
{
public override void Execute(INotification notification)
{
//菜單代理
MenuProxy menuProxy = new MenuProxy();
Facade.RegisterProxy(menuProxy);
//客戶端代理
ClientProxy clientProxy = new ClientProxy();
Facade.RegisterProxy(clientProxy);
//服務員代理
WaiterProxy waitProxy = new WaiterProxy();
Facade.RegisterProxy(waitProxy);
//廚師代理
CookProxy cookProxy = new CookProxy();
Facade.RegisterProxy(cookProxy);
OrderProxy orderProxy = new OrderProxy();
Facade.RegisterProxy(orderProxy);
MainUI mainUI = notification.Body as MainUI;
if(null == mainUI)
throw new Exception("程序啟動失敗..");
Facade.RegisterMediator(new MenuMediator(mainUI.MenuView));
Facade.RegisterMediator(new ClientMediator(mainUI.ClientView));
Facade.RegisterMediator(new WaiterMediator(mainUI.WaitView));
Facade.RegisterMediator(new CookMediator(mainUI.CookView));
}
}
2.2.3 PureMVC通知系統(tǒng)代碼總結
PureMVC中通知的執(zhí)行分為兩種:中介者(Mediator)和具體的命令(Command),中介者是面向視圖(View)的執(zhí)行者阳液,調(diào)用INotification.HandleNotification方法來執(zhí)行具體的操作怕敬,命令是面向控制器(Controller)的執(zhí)行者,調(diào)用Execute來執(zhí)行具體的操作,本質(zhì)是一樣的帘皿,但是可以區(qū)分一下兩只的使用環(huán)境东跪,中介者用于視圖方面的通知和其他中介者之間的交互,但是命令應該用于系統(tǒng)功能級別,比如啟動程序虽填,或者是關閉程序等
PureMVC中通過反射獲取觀察者的類型來區(qū)分中介者丁恭、命令這兩種不同的通知類型
PureMVC框架總結
通過上一篇講解核心MVC類和這一篇通知系統(tǒng)的講解,大家應該對PureMVC有了一個大概的理解卤唉,通過看我Github的案例代碼涩惑,應該就可以入手PureMVC框架了,下面做一個PureMVC的總結桑驱。
- PureMVC是一個輕量級架構竭恬,但是它卻可以有效解耦,提供編碼效率熬的,提升部分代碼重用
- PureMVC對于超小型項目可能會導致代碼過于繁瑣痊硕,但是只要是團隊開發(fā),PureMVC可以幫你避免掉很多不規(guī)范
- PureMVC也是一種較為容易理解運行機制的框架押框,即便是新手也可以很快入門岔绸,在團隊中還是值得使用的
文章轉(zhuǎn)自CSDN
原文鏈接:https://blog.csdn.net/qq_29579137/article/details/73717882