## 什么是消息機制?





23333333,讓我先笑一會。
## 為什么用消息機制?
三個字,解!!!!耦!!!!合!!!!。
## 我的框架中的消息機制用例:
1.接收者
Receiver.cs
```cs
using UnityEngine;
namespace QFramework.Example
{
/// <summary>
/// 教程地址:http://liangxiegame.com/post/5/
/// </summary>
public class Receiver : MonoBehaviour, IMsgReceiver
{
// Use this for initialization
private void Awake()
{
this.RegisterLogicMsg("Receiver Show Sth", ReceiveMsg);
}
private void ReceiveMsg(object[] args)
{
foreach (var arg in args)
{
Log.I(arg);
}
}
}
}
```
2.發送者
```cs
using UnityEngine;
namespace QFramework.Example
{
/// <summary>
/// 教程地址:http://liangxiegame.com/post/5/
/// </summary>
public class Sender : MonoBehaviour, IMsgSender
{
void Update()
{
this.SendLogicMsg("Receiver Show Sth", "你好", "世界");
}
}
}
```
3.運行結果

使用起來幾行代碼的事情,實現起來就沒這么簡單了。
## 如何實現的?
可以看到接收者實現了接口IMsgReceiver,發送者實現了接口 IMsgSender。
那先看下這兩個接口定義。
IMsgReceiver.cs:
```cs
namespace QFramework
{
public interface IMsgReceiver
{
}
}
```
IMsgSender.cs:
```cs
namespace QFramework
{
public interface IMsgSender
{
}
}
```
毛都沒有啊。也沒有 SendLogicMsg 或者 ReceiveLogicMsg 方法的定義啊。
答案是使用 C# this 的擴展方式實現接口方法。
不清楚的童鞋請百度 C# this 擴展,有好多文章就不介紹了。
以上先告一段落,先介紹個重要的角色,MsgDispatcher (消息分發器)。
貼上第一部分代碼:
```cs
/// <summary>
/// 消息分發器
/// C# this擴展 需要靜態類
/// 教程地址:http://liangxiegame.com/post/5/
public static class MsgDispatcher
{
/// <summary>
/// 消息捕捉器
/// </summary>
private class LogicMsgHandler
{
public readonly IMsgReceiver Receiver;
public readonly Action<object[]> Callback;
public LogicMsgHandler(IMsgReceiver receiver, Action<object[]> callback)
{
Receiver = receiver;
Callback = callback;
}
}
/// <summary>
/// 每個消息名字維護一組消息捕捉器。
/// </summary>
static readonly Dictionary<string, List<LogicMsgHandler>> mMsgHandlerDict =
new Dictionary<string, List<LogicMsgHandler>>();
```
讀注釋!!!
貼上注冊消息的代碼
```cs
/// <summary>
/// 注冊消息,
/// 注意第一個參數,使用了C# this的擴展,
/// 所以只有實現IMsgReceiver的對象才能調用此方法
/// </summary>
public static void RegisterLogicMsg(this IMsgReceiver self, string msgName, Action<object[]> callback)
{
// 略過
if (string.IsNullOrEmpty(msgName))
{
Log.W("RegisterMsg:" + msgName + " is Null or Empty");
return;
}
// 略過
if (null == callback)
{
Log.W("RegisterMsg:" + msgName + " callback is Null");
return;
}
// 略過
if (!mMsgHandlerDict.ContainsKey(msgName))
{
mMsgHandlerDict[msgName] = new List<LogicMsgHandler>();
}
// 看下這里
var handlers = mMsgHandlerDict[msgName];
// 略過
// 防止重復注冊
foreach (var handler in handlers)
{
if (handler.Receiver == self && handler.Callback == callback)
{
Log.W("RegisterMsg:" + msgName + " ayready Register");
return;
}
}
// 再看下這里
handlers.Add(new LogicMsgHandler(self, callback));
}
```
為了節省您時間,略過部分的代碼就不要看了,什么?!!你都看了!!!! 23333
發送消息相關的代碼
```cs
/// <summary>
/// 發送消息
/// 注意第一個參數
/// </summary>
public static void SendLogicMsg(this IMsgSender sender, string msgName, params object[] paramList)
{
// 略過,不用看
if (string.IsNullOrEmpty(msgName))
{
Log.E("SendMsg is Null or Empty");
return;
}
// 略過,不用看
if (!mMsgHandlerDict.ContainsKey(msgName))
{
Log.W("SendMsg is UnRegister");
return;
}
// 開始看!!!!
var handlers = mMsgHandlerDict[msgName];
var handlerCount = handlers.Count;
// 之所以是從后向前遍歷,是因為 從前向后遍歷刪除后索引值會不斷變化
// 參考文章,http://www.2cto.com/kf/201312/266723.html
for (var index = handlerCount - 1; index >= 0; index--)
{
var handler = handlers[index];
if (handler.Receiver != null)
{
Log.W("SendLogicMsg:" + msgName + " Succeed");
handler.Callback(paramList);
}
else
{
handlers.Remove(handler);
}
}
}
```
OK 主要的部分全都貼出來啦。
## 可以改進的地方:
* 目前整個游戲的消息都由一個字典維護,可以改進為每個模塊維護一個字典或者其他方式。
* 消息名字類型由字符串定義的,可以改成枚舉轉 unsigned int 方式。
* 歡迎補充。
## 坑:
* 如果是 MonoBehaviour 注冊消息之后,GameObject Destroy 之前一定要注銷消息,之前的解決方案是,自定義一個基類來維護該對象已經注冊的消息列表,然后在基類的 OnDestory 時候遍歷卸載。
* 歡迎補充。
轉載請注明地址:涼鞋的筆記:[liangxiegame.com](http://liangxiegame.com)
## 更多內容
* QFramework 地址:[https://github.com/liangxiegame/QFramework](https://github.com/liangxiegame/QFramework)
* QQ 交流群:[623597263](http://shang.qq.com/wpa/qunwpa?idkey=706b8eef0fff3fe4be9ce27c8702ad7d8cc1bceabe3b7c0430ec9559b3a9ce66)
* **Unity 進階小班**:
* 主要訓練內容:
* 框架搭建訓練(第一年)
* 跟著案例學 Shader(第一年)
* 副業的孵化(第二年、第三年)
* 權益、授課形式等具體詳情請查看[《小班產品手冊》](https://liangxiegame.com/master/intro):https://liangxiegame.com/master/intro
* 關注公眾號:liangxiegame 獲取第一時間更新通知及更多的免費內容。

- 正文
- Unity 游戲框架搭建 2017(一)概述
- Unity 游戲框架搭建 2017(二)單例的模板
- Unity 游戲框架搭建 2017(三)MonoBehaviour 單例的模板
- Unity 游戲框架搭建 2017(四)簡易有限狀態機
- Unity 游戲框架搭建 2017(五)簡易消息機制
- Unity 游戲框架搭建 2017 (六) 關于框架的一些好文和一些思考
- Unity 游戲框架搭建 2017 (七) 減少加班利器-QApp類
- Unity 游戲框架搭建 2017 (八) 減少加班利器-QLog
- Unity 游戲框架搭建 2017 (九) 減少加班利器-QConsole
- Unity 游戲框架搭建 2017 (十) QFramework v0.0.2小結
- Unity 游戲框架搭建 2017 (十一) 簡易 AssetBundle 打包工具 (一)
- Unity 游戲框架搭建 2017 (十二) 簡易 AssetBundle 打包工具 (二)
- Unity 游戲框架搭建 2017 (十三) 無需繼承的單例的模板
- Unity 游戲框架搭建 2017 (十四) 優雅的 QSingleton (零) QuickStart
- Unity 游戲框架搭建 2017 (十四) 優雅的 QSingleton (一) Singleton 單例實現
- Unity 游戲框架搭建 2017 (十四) 優雅的 QSingleton (二) MonoSingleton單例實現
- Unity 游戲框架搭建 2017 (十四) 優雅的 QSignleton (三) 通過屬性器實現 Singleton
- Unity 游戲框架搭建 2017 (十四) 優雅的 QSingleton (四) 屬性器實現 Mono 單例
- Unity 游戲框架搭建 2017 (十四) 優雅的 QSingleton (五) 優雅地進行GameObject命名
- Unity 游戲框架搭建 2017 (十五) 優雅的 QChain (零)
- Unity 游戲框架搭建 2017 (十六) v0.0.3 架構調整
- Unity 游戲框架搭建 2017 (十七) 靜態擴展GameObject 實現鏈式編程
- Unity 游戲框架搭建 2017 (十八) 靜態擴展 + 泛型實現 transform 的鏈式編程
- Unity 游戲框架搭建 2017 (十九) 簡易對象池
- Unity 游戲框架搭建 2017 (二十) 安全的對象池
- Unity 游戲框架搭建 2017 (二十一) 使用對象池時的一些細節
- Unity 游戲框架搭建 2017 (二十二) 簡易引用計數器
- Unity 游戲框架搭建 2017 (二十三) 重構小工具 Platform
- Unity 游戲框架搭建 2017 (二十四) 小結