Lua的語法非常靈活, 使用他的metatable及metamethod可以模擬出很多語言的特性.
C#中我們這樣使用事件:
xxx.Click += new System.EventHandler(xxx_Click); private void xxx_Click(object sender, EventArgs e) { /**/ }
在Lua中要達到同樣的效果, 并且支持事件多播機制, 其關鍵在于重寫metamethod __call, 從而使得不光function才能被調用, table也能夠被調用.
主要思想就是, 通過一個table來保存注冊事件的若干響應函數, 然后拿table當function一樣來調用, 重寫__call后, 實現調用table時遍歷執行table中的注冊方法.
需要在lua5.0 或 lua.net上執行, lua 5.1略有改動.
1 --test.lua
2 do
3
4 --事件原型對象, 所有事件由此原型生成
5 Event = {}
6
7 function Event:New()
8 local event = {}
9 setmetatable(event, self)
10 --覆蓋__index邏輯
11 self.__index = self
12 --覆蓋__call邏輯
13 self.__call = self.Call
14 return event
15 end
16
17 --事件注冊, 通過此方法將響應方法注冊到事件上.
18 --@source:響應方法的所屬對象
19 --@func:響應方法
20 function Event:Add(source, func)
21 table.insert(self, {source, func})
22 end
23
24 --內部方法, 重寫了默認__call邏輯, 當event被觸發調用時, 循環執行event中注冊的響應方法
25 --@table:對象產生調用時將本身傳入
26 --@...:調用參數
27 function Event.Call(table, ...)
28 for _, item in ipairs(table) do
29 --item[1]就是source, item[2]就是func響應方法
30 --lua 5.1中無需使用unpack(arg), 直接使用...即可
31 item[2](item[1], unpack(arg))
32 end
33 end
34
35 ------------------以下為測試用例-----------------------
36
37 --創建一個window對象, 注冊按鈕的點擊事件
38 Window = {
39 Name = "Simonw's Window",
40 }
41
42 function Window:Init()
43 --注冊事件, self即Window, 對象來源.
44 Button.ClickEvent:Add(self, self.Button_OnClick)
45 end
46
47 --響應事件方法, sender即是傳來的Button對象
48 function Window:Button_OnClick(sender)
49 print(sender.Name.." Click On "..self.Name)
50 end
51
52 --創建一個button對象, 擁有ClickEvent這樣的事件
53 Button = {
54 Name = "A Button",
55 --創建事件
56 ClickEvent = Event:New(),
57 }
58
59 --執行點擊按鈕的動作
60 function Button:Click()
61 print('Click begin')
62 --觸發事件, self即sender參數
63 self.ClickEvent(self)
64 print('Click end')
65 end
66
67 --從這里執行
68 Window:Init()
69 Button:Click()
70 --[[
71 執行結果:
72 > dofile 'test.lua'
73 Click begin
74 A Button Click On Simonw's Window
75 Click end
76 ]]
77
78 end
不含病毒。www.avast.com |
留言列表