Events and event handlers.. pros and cons
BlitzMax Forums/BlitzMax Programming/Events and event handlers.. pros and cons
| ||
Hey people. Here's just a question to see some of your opinions and see if I can improve on my ways of dealing with events. I never got into the whole Blitzmax EventHook mechanism myself. It always seemed a bit odd to me. The whole message pump mechanism is not my cup of tea. I've been using my own eventhandling system for quite a while now and with success, as it allows me to expose events in a class/type pretty much the same way as you see them in C#. Also have multiple hooks for the same event all neatly contained in one place. What i'm wondering is what one would consider a better solution and in particular: why? Here's an example: Type TApp '// These are the events I want to expose. '// They are simple lists that let me add/remove function pointers '// to event handlers whenever i want and however many I want. Field Load:TList; Field Unload:TList; Method New() Self.Load = New TList; Self.Unload = New TList; End Method Method Delete() Self.Load.Clear(); Self.Unload.Clear(); End Method '// these are called in order to trigger the events whenever required. '// loop through all hooked eventhandlers and execute them. Method OnLoad(e:TEventArgs) For Local eh:TEventHandler = EachIn Self.Load eh.Execute(Self, e); Next End Method Method OnUnload(e:TEventArgs) For Local eh:TEventHandler = EachIn Self.Unload eh.Execute(Self, e); Next End Method '// Run method does some arbitrary stuff and calls load/unload Method Run() Print("running app. Performing custom loading code"); Self.OnLoad(TEventArgs.Create(123, "foo", 32.1)); '// run main app here.. Print("stopping app. Performing custom cleanup code."); Self.OnUnload(TEventArgs.Create(321, "bar", 12.3)); End Method End Type '// The TEventHandler type Type TEventHandler Field Execute:Int(sender:Object, e:TEventArgs); Function Create:TEventHandler(handler:Int(sender:Object, e:TEventArgs)) Local eh:TEventHandler = New TEventHandler; eh.Execute = handler; Return eh; End Function End Type '// The TEventArgs type. '// In order to send any kind of custom arguments to the event handler functions, '// you can simply add fields to this class or create custom EventArgs types that deal '// with different events/situations. Type TEventArgs Field A:Int, B:String, C:Float; Function Create:TEventArgs(a:Int, b:String, c:Float) Local e:TEventArgs = New TEventArgs; e.A = a; e.B = b; e.C = c; Return e; End Function End Type To see it working, this is all that's needed: SuperStrict Framework brl.basic Import brl.linkedlist Local app:TApp = New TApp; '// hook the events app.Load.AddLast(TEventHandler.Create(HandleLoad)); app.Unload.AddLast(TEventHandler.Create(HandleUnload)); '// Run the app app.Run(); '// These contain the code that actually handles the triggered events. Function HandleLoad(sender:Object, e:TEventArgs) Print(e.A + ", " + e.B + ", " + e.C); End Function Function HandleUnload(sender:Object, e:TEventArgs) Print(e.A + ", " + e.B + ", " + e.C); End Function Basically, all this does is maintain a list of function pointers which get executed whenever an event is triggered and passes them some arbitrary set of arguments as defined in the TEventArgs type. One of the drawbacks of this system is that eventhandlers can only be Static functions and not methods because they are function pointers. This is inconvenient at times, but hasn't posed a real problem for me yet. In the example, the current instance of TApp is passed as the sender argument, so any operations on the instance that triggered this event can still be performed normally. Another drawback is that an event requires quite a bit of code to create, but once it's there it's very easy to use. This makes it particularly useful in situations where you have reusable classes with lots of events. For short pieces of code however, this may not be the most ideal solution. Any thoughts or improvements on this? |