到目前为止,我们使用接口+静态拓展的方式为每一个层级的接口增加了使用规则。还有一个规则设置还没完成,那就是事件的使用规则。

我们目前的事件基类如下

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//使用拓展方法,继承IUnregister接口后并实现的同时将表现层对象也放进来
{
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//用来存储一个TypeEvent各种各样的注册监听
{
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()
{
//EventA使用最普通的监听,需要在OnDestroy里面注销且置空
m_TypeEventSystem.Register<EventA>(OnEventA);
//EventB使用lambda监听加拓展方法,不需要在Ondestroy调用Unregister
m_TypeEventSystem.Register<EventB>(b =>
{
Debug.Log("OnEventB:" + b.ParamB);
}).UnregisterWhenGameObjectDestroyed(gameObject);
//EventC和EventD使用相同的接口,我们通过接口注册TypeEvent
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文件夹中新建两个脚本,分别是

ICanSendEventICanRegisterEvent

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继承ICanSendEventICanRegisterEvent

ICommand继承ICanSendEvent

IController继承ICanRegisterEvent

直接在脚本文件中添加继承即可,这里省略代码

应用TypeEventSystem

修改注册(监听)部分

我们放弃之前的BaseEvent,使用TypeEventSystem,重构一下代码

修改GameEndEvent脚本

1
2
3
4
5
6
7
namespace FrameWorkDesign.Example
{
public class GameEndEvent //只需要提供EventType就够了
{

}
}

修改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可以发送事件