到目前为止,我们使用接口+静态拓展的方式为每一个层级的接口增加了使用规则。还有一个规则设置还没完成,那就是事件的使用规则。
我们目前的事件基类如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 using System;namespace FrameWorkDesign { public class BaseEvent <T > where T : BaseEvent <T > { private static Action m_OnEvent; public static void Register (Action onEvent ) { m_OnEvent += onEvent; } public static void Unregister (Action onEvent ) { m_OnEvent -= onEvent; } public static void Trigger () { m_OnEvent?.Invoke(); } } }
这套事件基类有两个问题,一个是事件不能传递参数,一个是管理对象无法分组。
我们直接实现一个新的事件管理机制
TypeEventSystem 在FrameworkDesign——Framework——Event文件夹内新建TypeEventSystem
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 using System.Collections.Generic;using UnityEngine;using System;namespace FrameWorkDesign { public interface ITypeEventSystem { void Send <T >() where T : new () ; void Send <T >(T e ) ; IUnregister Register <T >(Action<T> onEvent ) ; void Unregister <T >(Action<T> onEvent ) ; } public interface IUnregister { void Unregister () ; } public struct TypeEventSystemUnRegister <T > : IUnregister { public ITypeEventSystem TypeEventSystem {get ;set ;} public Action <T > OnEvent {get ;set ;} public void Unregister () { TypeEventSystem.Unregister<T>(OnEvent); TypeEventSystem = null ; OnEvent = null ; } } public class UnregisterOnDestroyTrigger : MonoBehaviour { HashSet<IUnregister> m_Unregisters = new HashSet<IUnregister>(); public void AddUnregister (IUnregister unregister ) { m_Unregisters.Add(unregister); } private void OnDestroy () { foreach (var unregister in m_Unregisters) { unregister.Unregister(); } m_Unregisters.Clear(); } } public static class UnregisterExtension { public static void UnregisterWhenGameObjectDestroyed (this IUnregister unregister,GameObject gameObject ) { var trigger = gameObject.GetComponent<UnregisterOnDestroyTrigger>(); if (!trigger) { trigger = gameObject.AddComponent<UnregisterOnDestroyTrigger>(); } trigger.AddUnregister(unregister); } } public class TypeEventSystem : ITypeEventSystem { public interface IRegistrations { } public class Registrations <T > : IRegistrations { public Action<T> OnEvent = e => { }; } Dictionary<Type, IRegistrations> m_EventRegistration = new Dictionary<Type, IRegistrations>(); public IUnregister Register <T >(Action<T> onEvent ) { var type = typeof (T); IRegistrations registrations; if (m_EventRegistration.TryGetValue(type, out registrations)) { } else { registrations = new Registrations<T>(); m_EventRegistration.Add(type, registrations); } (registrations as Registrations<T>).OnEvent += onEvent; return new TypeEventSystemUnRegister<T>() { OnEvent = onEvent, TypeEventSystem = this }; } public void Send <T >() where T : new () { var e = new T(); Send<T>(e); } public void Send <T >(T e ) { var type = typeof (T); IRegistrations registrations; if (m_EventRegistration.TryGetValue(type, out registrations)) { (registrations as Registrations <T >).OnEvent (e ) ; } } public void Unregister <T >(Action<T> onEvent ) { var type = typeof (T); IRegistrations registrations; if (m_EventRegistration.TryGetValue(type, out registrations)) { (registrations as Registrations<T>).OnEvent -= onEvent; } } } }
TypeEventSystem根据每一个TypeEvent将其被监听的方法们都放在Registration
类里
TypeEventSystem本身不是一个泛型类,它只提供泛型方法,所以会有Registrations<T>
这个内部类,要是直接用Action,就不能区分不同的TypeEvent了,TypeEventSystem不做泛型的原因就是我们要把它整合进Architecture中,像IOCContainer一样使用。
IUnregister
接口是为了将TypeEventSystem
中的Unregister
剥离出来,然后我们在UnregisterOnDestroyTrigger
里面调用它,同时我们还给IUnregister
添加了UnregisterWhenGameObjectDestroyed
拓展方法以更方便地调用,这么做都是为了以后能简化使用,不用表现层在Destroy的时候再调用EventSystem这么麻烦。
TypeEventSystem示例 在FrameworkDesign——Example内新建Event文件夹,在其中新建一个TypeEventSystemExample场景和一个TypeEventSystemExample
脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 using UnityEngine;namespace FrameWorkDesign.Example { public class TypeEventSystemExample : MonoBehaviour { #region 定义几种事件类型(TypeEvent) public struct EventA { } public struct EventB { public int ParamB; } public interface IEventGroup { } public struct EventC : IEventGroup { } public struct EventD : IEventGroup { } #endregion private TypeEventSystem m_TypeEventSystem = new TypeEventSystem(); void Start () { m_TypeEventSystem.Register<EventA>(OnEventA); m_TypeEventSystem.Register<EventB>(b => { Debug.Log("OnEventB:" + b.ParamB); }).UnregisterWhenGameObjectDestroyed(gameObject); m_TypeEventSystem.Register<IEventGroup>(e => { Debug.Log(e.GetType()); }).UnregisterWhenGameObjectDestroyed(gameObject); } private void OnEventA (EventA obj ) { Debug.Log("OnEventA" ); } private void OnDestroy () { m_TypeEventSystem.Unregister<EventA>(OnEventA); m_TypeEventSystem = null ; } void Update () { if (Input.GetMouseButtonDown(0 )) { m_TypeEventSystem.Send<EventA>(); } if (Input.GetMouseButtonDown(1 )) { m_TypeEventSystem.Send<EventB>(new EventB() { ParamB = 123 }); } if (Input.GetKeyDown(KeyCode.Space)) { m_TypeEventSystem.Send<IEventGroup>(new EventC()); m_TypeEventSystem.Send<IEventGroup>(new EventD()); } } } }
TypeEventSystem和我们最开始实现的BaseEvent
的实现思路是不一样的
没有静态变量
不需要继承,我们自创的各种Event需要new一个TypeEventSystem然后注册进去(并且可以使用接口DIP)并添加监听。
TypeEventSystem纳入框架并添加约束 表现层监听底层内部事件,事件自底向上通知
IController作为表现层,可以监听事件
ICommand可以发送事件
ISystem可以发送和监听事件
IModel可以发送事件
Architecture中增加注册和发送事件的支持 整个System肯定要整合到Architecture中的,打开Architecture
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 using System;using System.Collections.Generic;namespace FrameWorkDesign { public interface IArchitecture { void SendEvent <T >() where T : new () ; void SendEvent <T >(T e ) ; IUnregister RegisterEvent <T >(Action<T> onEvent ) ; void UnregisterEvent <T >(Action<T> onEvent ) ; } public abstract class Architecture <T > : IArchitecture where T : Architecture <T >,new () { private ITypeEventSystem m_TypeEventSystem = new TypeEventSystem(); public IUnregister RegisterEvent <T >(Action<T> onEvent ) { return m_TypeEventSystem.Register<T>(onEvent); } public void UnregisterEvent <T >(Action<T> onEvent ) { m_TypeEventSystem.Unregister<T>(onEvent); } public void SendEvent <T >() where T : new () { m_TypeEventSystem.Send<T>(); } public void SendEvent <T >(T e ) { m_TypeEventSystem.Send<T>(e); } } }
添加Rule 像上一节所讲的那样,我们在FrameworkDesign——Framework——Architecture——Rule文件夹中新建两个脚本,分别是
ICanSendEvent
、ICanRegisterEvent
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 namespace FrameWorkDesign { public interface ICanSendEvent : IBelongToArchitecture { } public static class CanSendEventExtension { public static void SendEvent <T >(this ICanSendEvent self ) where T : new () { self.GetArchitecture().SendEvent<T>(); } public static void SendEvent <T >(this ICanSendEvent self,T e ) { self.GetArchitecture().SendEvent<T>(e); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 using System;namespace FrameWorkDesign { public interface ICanRegisterEvent : IBelongToArchitecture { } public static class CanRegisterEventExtension { public static IUnregister RegisterEvent <T >(this ICanRegisterEvent self,Action<T> onEvent ) { return self.GetArchitecture().RegisterEvent<T>(onEvent); } public static void UnregisterEvent <T >(this ICanRegisterEvent self, Action<T> onEvent ) { self.GetArchitecture().UnregisterEvent<T>(onEvent); } } }
给各层接口添加约束 IModel
继承ICanSendEvent
ISystem
继承ICanSendEvent
和ICanRegisterEvent
ICommand
继承ICanSendEvent
IController
继承ICanRegisterEvent
直接在脚本文件中添加继承即可,这里省略代码
应用TypeEventSystem 修改注册(监听)部分 我们放弃之前的BaseEvent
,使用TypeEventSystem,重构一下代码
修改GameEndEvent
脚本
1 2 3 4 5 6 7 namespace FrameWorkDesign.Example { public class GameEndEvent { } }
修改GameStartEvent
脚本
1 2 3 4 5 6 7 namespace FrameWorkDesign.Example { public class GameStartEvent { } }
修改GameRoot
脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 using UnityEngine;namespace FrameWorkDesign.Example { public class GameRoot : MonoBehaviour ,IController { private void Awake () { this .RegisterEvent<GameStartEvent>(OnGameStart); } private void OnGameStart (GameStartEvent e ) { transform.Find("Enemies" ).gameObject.SetActive(true ); } void OnDestroy () { this .UnregisterEvent<GameStartEvent>(OnGameStart); } IArchitecture IBelongToArchitecture.GetArchitecture() { return PointGame.Interface; } } }
修改UIRoot
脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 using UnityEngine;namespace FrameWorkDesign.Example { public class UIRoot : MonoBehaviour ,IController { void Start () { this .RegisterEvent<GameEndEvent>(OnGameEnd); } private void OnGameEnd (GameEndEvent e ) { transform.Find("Canvas/Panel_GamePass" ).gameObject.SetActive(true ); } void OnDestroy () { this .UnregisterEvent<GameEndEvent>(OnGameEnd); } IArchitecture IBelongToArchitecture.GetArchitecture() { return PointGame.Interface; } } }
修改发送(广播)部分 修改KillEnemyCommand
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 namespace FrameWorkDesign.Example { public class KillEnemyCommand : AbstractCommand { protected override void OnExecute () { var gameModel = this .GetModel<IGameModel>(); gameModel.KillCount.Value++; if (gameModel.KillCount.Value == 9 ) { this .SendEvent<GameEndEvent>(); } } } }
修改StartGameCommand
1 2 3 4 5 6 7 8 9 10 namespace FrameWorkDesign.Example { public class StartGameCommand : AbstractCommand { protected override void OnExecute () { this .SendEvent<GameStartEvent>(); } } }
至此,重构完成
总结 表现层监听底层内部事件,事件自底向上通知
IController作为表现层,可以监听事件
ICommand可以发送事件
ISystem可以发送和监听事件
IModel可以发送事件