Unity框架设计(一) 消息处理框架

Unity框架设计(一) 消息处理框架

关于Unity的原生消息机制

为了降低耦和,Unity自带了消息机制。主要体现在如下三个方法:
SendMessage, SendMessageUpwards, BroadcastMessage
但是我们平时几乎不会使用它们,主要有如下几点缺陷:

  1. 内部使用反射,性能较差
  2. 严重依赖字符串,无法在编译阶段实现类型安全
  3. 只有继承自MonoBehaviour才可以调用
  4. 可以调用私有方法,破坏封装性
    所以开发游戏过程中构建一套自己的消息处理机制是必不可少的

实现自己的消息处理框架

那么现在可以针对这些缺陷去实现自己的消息处理框架了,基于C#的委托去实现,性能上和安全性上都远远强过Unity的原生消息传递机制。

一般来讲我不喜欢使用单例模式实现除非逼不得已,因为不容易控制单例的生存周期,很难有一个合理的初始化顺序。同时为了兼顾易用性和安全性,所以我们使用泛型静态类来实现

首先写一个异常,抛出该框架内部的异常

public class MessageException : Exception {
        public MessageException(string message, Exception innerException) : base(message, innerException) { }
        public MessageException(string message):base(message) { }
        public MessageException() : base() { }
}

接下来是框架部分

namespace ZCC.MessageCenter {

    /// 消息中心的异常
    public class MessageException : Exception {
        public MessageException(string message, Exception innerException) : base(message, innerException) { }
        public MessageException(string message):base(message) { }
        public MessageException() : base() { }
    }

    /// 消息中心
    /// 消息枚举 每种类型的消息枚举都有一个消息中心
    public static class MessageCenter<TMessage> where TMessage: struct {

        /// 已注册的消息字典
        private static Dictionary<TMessage, EventHandler> _dicMessages = new Dictionary<TMessage, EventHandler>();

        /// 向某消息注册监听者 
        public static void AddListener(TMessage message, EventHandler messageHandler) {
            if (!_dicMessages.ContainsKey(message))
                _dicMessages.Add(message, null);
            _dicMessages[message] += messageHandler;
        }

        /// 注销某消息的某个监听者 
        public static void RemoveListener(TMessage message, EventHandler messageHandler) {
            if (!_dicMessages.ContainsKey(message)) {
                Debug.LogError(typeof(TMessage).Name + ":" + "[RemoveListener]不存在此messageKey:[" + message.ToString() + "]");
                return;
            }
            _dicMessages[message] -= messageHandler;

        }

        /// 发送消息给所有监听者
        public static void SendMessage(TMessage message, object sender, EventArgs eventArgs) {
            if (!_dicMessages.ContainsKey(message)) {
                Debug.LogError(typeof(TMessage).Name+":"+"[SendMessage]不存在此messageKey:["+ message.ToString()+"]");
                return;
            }
            Delegate[] invocationList = _dicMessages[message].GetInvocationList();
            foreach (Delegate invocation in invocationList) {
                try {
                    (invocation as EventHandler)(sender, eventArgs);
                }
                catch(Exception e) {
                    Debug.LogError(e);
                    throw e;
                }
            }
        }
    }
}

TMessage作为泛型参数,被限定为值类型,使用枚举作为一类消息的标识,代码看起来可读性很高。不同的类型参数有自己的消息字典,维护各自内部的消息处理。 比如为了传递UI消息,我们先设计一个UIMessage枚举,用来枚举所有UI消息

public enum UIMessage {
    /// 
    ENull = 0,
    /// 打开窗口
    OpenForm = 1,
    /// 关闭窗口
    CloseForm = 2
}

然后针对自己的业务逻辑设计传递的消息类,该类需要继承自EventArgs

public class UIEventArgs: EventArgs{
	public string FormName;
	public UIEventArgs(string formName){	
		this.FormName = formName;
	}
}

具体用法也不必赘述了, 下面写一个小例子

public class Example: MonoBehaviour {
	private void Awake( ){	
		//向OpenForm注册监听者
		MessageCenter<UIMessage>.AddListener(UIMessage.OpenForm, OnOpenForm);
		//向所有注册OpenForm的监听者发送消息
		MessageCenter<UIMessage>.SendMessage(UIMessage.OpenForm,new UIEventArgs("LoginForm"));
	}

	private void OnOpenForm(object sender, this, EventArgs eventArgs){
	    print("打开窗口"+(eventArgs as UIEventArgs).FormName);
	}
}

当然还有一些地方可以扩展改进,欢迎留言!

你可能感兴趣的:(Unity3D)