观察者模式,绝对是游戏中十分重要的一种模式,运用这种模式,可以让游戏模块间的通信变得简单,耦合度也会大大降低,下面讲解如何利用C#实现事件通知系统。
补充,首先说下这个系统的实现原理,不然一头扎进去就难受了,这个系统的关键就在于两个类,EventCenter 和Handler,她们关系如下:
首先定义两个接口,IEventCenter 和IEventHandlerManager,代码如下:
1 public interface IEventCenter : IDestroy 2 { 3 bool AddEventListener(Enum EventType, EventHandler handler); 4 5 bool RemoveEventListener(Enum EventType, EventHandler handler); 6 7 //触发事件 8 void TriggerEvent(IEvent e); 9 10 //广播事件 11 void BroadCastEvent(); 12 13 }
1 public delegate void EventHandler(IEvent evt);//顺带定义了下事件委托。 2 3 public interface IEventHandlerManger : IEvent,IDestroy 4 { 5 bool AddHandler(EventHandler eventHandler); 6 7 bool RemoveHandler(EventHandler eventHandler); 8 9 void BroadCastEvent(IEvent evt); 10 11 void Clear(); 12 }
定义完两个接口后,就分别开始实现两个接口,两个接口的实现分别为EventCenter 和EventHandlerManager,代码如下 1 public class EventCenter : MonoSingleton<EventCenter>, IEventCenter
{
3 private Dictionary<Enum, IEventHandlerManger> DictHandler = new Dictionary<Enum, IEventHandlerManger>();
4
5 private SafeQuene<IEvent> eventQuene = new SafeQuene<IEvent>();
6
7
8 public bool AddEventListener(Enum EventType, EventHandler handler)
9 {
10 bool isSuccessed;
//如果不包含EventType,就将其加入到字典中,同时新建一个EventHandlerManager()
11 if (!DictHandler.ContainsKey(EventType))
12 {
13 DictHandler[EventType] = new EventHandlerManager();
14 }
//然后将handler加入到新创建的EventHandlerManager中去。
15 isSuccessed = DictHandler[EventType].AddHandler(handler);
16
17 return isSuccessed;
18 }
19
20 public bool RemoveEventListener(Enum EventType, EventHandler handler)
21 {
22 if (DictHandler.ContainsKey(EventType))
23 {
24 DictHandler.Remove(EventType);
25 return true;
26 }
27 else
28 {
29 return false;
30 }
31 }
32
33 public void TriggerEvent(IEvent e)
34 {
35 this.eventQuene.EnQuene(e);
36 }
37
38
39 #region 广播事件相关
40
41
42 public void Update()
43 {
44 BroadCastEvent();
45 }
46 public void BroadCastEvent()
47 {
48 if (eventQuene.Count<1)
49 {
50 return;
51 }
52
53 IEvent e = eventQuene.DeQuene();
54
55 BroadCastEvent(e);
56 }
57
58 public void BroadCastEvent(IEvent e)
59 {
60 if (e == null)
61 {
62 return;
63 }
64
65 Enum type = e.EventType;
66
67 if (!DictHandler.ContainsKey(type))
68 {
69 e.DestroySelf();
70 }
71
72 DictHandler[type].BroadCastEvent(e);
73 e.DestroySelf();
74
75 }
76
77 #endregion
78
79 #region 清除数据相关
80
81
82 public void DestroySelf()
83 {
84 ClearEvenQueneAndDictHandler();
85 }
86
87 public void OnDestroy()
88 {
89 ClearEvenQueneAndDictHandler();
90 }
91
92 public void ClearEventQuene()
93 {
94 eventQuene.Clear();
95 }
96
97 public void ClearEvenQueneAndDictHandler()
98 {
99 DictHandler.Clear();
100 ClearEventQuene();
101 }
102
103 #endregion
104 }
1 public class EventHandlerManager : IEventHandlerManger 2 { 3 private Enum _EventType; 4 5 private List<EventHandler> handler = new List<EventHandler>(); 6 7 public Enum EventType 8 { 9 get 10 { 11 return _EventType; 12 } 13 } 14 15 public bool AddHandler(EventHandler eventHandler) 16 { 17 if (handler.Contains(eventHandler)) 18 { 19 return false; 20 } 21 22 handler.Add(eventHandler); 23 return true; 24 } 25 26 public bool RemoveHandler(EventHandler eventHandler) 27 { 28 if (!handler.Contains(eventHandler)) 29 { 30 return false; 31 } 32 33 handler.Remove(eventHandler); 34 return true; 35 } 36 37 public void BroadCastEvent(IEvent evt) 38 { 39 List<EventHandler> list = new List<EventHandler>(); 40 list.AddRange(handler); 41 42 foreach (EventHandler item in list) 43 { 44 item(evt); 45 } 46 } 47 48 49 public void Clear() 50 { 51 handler.Clear(); 52 } 53 54 public void DestroySelf() 55 { 56 if (handler !=null) 57 { 58 Clear(); 59 handler = null; 60 } 61 } 62 63 64 }
ok,补充说明一下,IEvent接口很简单,里面定义了一个Enum EventType的Get方法,IDestroy接口则定义了一个DestroySelf()的方法。safeQuene<T>是一个线程安全的Quene<T>,其余和Quene<T>一样。
运用这套事件广播系统也十分简单,首先,在需要有事件通知的地方预定一个enum类型,比如:
public enum FBIEvent { TheyHaveGuns = 1, TheyUseBoom =2, TheyAreCute =3, }
然后需要定义这三个枚举类型对应的操作函数,例如:
1 public class FBI 2 { 3 void HavaGun(IEvent e) 4 { 5 Debug.Log("yellow gun!"); 6 } 7 8 void UseBoom(IEvent e) 9 { 10 Debug.Log("yellow gun!"); 11 } 12 13 void TheyCute(IEvent e) 14 { 15 Debug.Log("Impossible"); 16 } 17 }
最后,只需要调用EventCenter的AddEventListener()方法,将其注册进入EventCenter的DicrtHandler 字典中,就大功告成了。
触发流程:
1 其他方法,触发EventCenter的TriggerEvent(IEvent e)方法。
2 EventCenter 的eventQuene会增加一个实现了IEvent接口的类。
3 在Update()中不停执行的BroadCastEvent()函数,会从eventQuene中取出类,然后执行BroadCastEvent(IEvent e)方法。
4 根据传入的EventType类型,将从DirctHandler中取出对应的IEventHandlerManager对象,然后执行其BroadCastEvent(EventHandler hanlder)方法,
这里根据多态,实际上执行的是EventHandleManager类的BroadCastEvent(EventHandler hanlder)方法。
5 因为EventHandleManager的BroadCastEvent(EventHandler hanlder)类其实就是将该类中的List Handler中的委托全部取出来,然后执行,又因为其实
这里的每个委托在我们注册的时候,就绑定了相应的处理方法,因此,此刻执行的委托,其实就是执行的我们绑定的具体的方法。