Delegates


Once upon a time, in a strange land south of here, lived Peter. Peter was a diligent worker who would readily accept requests from his boss. However, his boss was a mean, untrusting man who insisted on steady progress reports . Because Peter did not want his boss standing in his office looking over his shoulder, Peter promised to notify his boss whenever his work progressed. Peter implemented this promise by periodically calling his boss back via a typed reference like so:

 
 Class Worker   Dim myboss As Boss   Public Sub Advise(theboss As Boss)       Me.myboss = theboss   End Sub   Public Sub DoWork()       Console.WriteLine("Worker: work started")       If Not (myboss Is Nothing) Then myboss.WorkStarted()       Console.WriteLine("Worker: work progressing")       If Not (myboss Is Nothing) Then myboss.WorkProgressing()       Console.WriteLine("Worker: work completed")       If Not (myboss Is Nothing) Then           Dim grade As Integer = myboss.WorkCompleted()           Console.WriteLine("Worker grade = " & _ grade.ToString())       End If   End Sub End Class Class Boss   Public Sub WorkStarted()       ' boss doesn't care   End Sub   Public Sub WorkProgressing()       ' boss doesn't care   End Sub   Public Function WorkCompleted() As Integer       Console.WriteLine("It's about time!")       Return 2 ' out of 10   End Function End Class Class Universe   Shared Sub Main()       Dim peter As Worker = New Worker()       Dim theboss As Boss = New Boss()       peter.Advise(theboss)       peter.DoWork()       Console.WriteLine("Main: worker completed work")       Console.ReadLine()   End Sub End Class 

Interfaces

Now Peter was a special person. Not only was he able to put up with his mean-spirited boss, but he also had a deep connection with the universe around him. So much so that he felt that the universe was interested in his progress. Unfortunately, there was no way for Peter to advise the universe of his progress unless he added a special Advise method and special callbacks just for the universe, in addition to keeping his boss informed. What Peter really wanted to do was to separate the list of potential notifications from the implementation of those notification methods. And so he decided to split the methods into an interface:

 
 Interface IWorkerEvents   Sub WorkStarted()   Sub WorkProgressing()   Function WorkCompleted() As Integer End Interface Class Worker   Private myevents As IWorkerEvents   Public Sub Advise(events As IWorkerEvents)       Me.myevents = events   End Sub   Public Sub DoWork()       Console.WriteLine("Worker: work started")       If Not (myevents Is Nothing) Then myevents.WorkStarted()       Console.WriteLine("Worker: work progressing")       If Not (myevents Is Nothing) Then myevents.WorkProgressing()       Console.WriteLine("Worker: work completed")       If Not (myevents Is Nothing) Then           Dim grade As Integer = myevents.WorkCompleted()           Console.WriteLine("Worker grade = " & _ grade.ToString())       End If   End Sub End Class Class Boss   Implements IWorkerEvents   Public Sub WorkStarted() Implements IWorkerEvents.WorkStarted       ' boss doesn't care   End Sub   Public Sub WorkProgressing() _ Implements IWorkerEvents.WorkProgressing ' boss doesn't care   End Sub   Public Function WorkCompleted() As Integer _       Implements IWorkerEvents.WorkCompleted       Console.WriteLine("It's about time!")       Return 3 ' out of 10   End Function End Class 

Unfortunately, Peter was so busy talking his boss into implementing this interface that he didn't get around to notifying the universe, but he planned to get to that as soon as possible. At least he'd abstracted the reference of his boss far away from him so that others who implemented the IWorkerEvents interface could be notified of his work progress.

Still, his boss complained bitterly. "Peter!" his boss fumed. "Why are you bothering to notify me when you start your work or when your work is progressing?!? I don't care about those events. Not only do you force me to implement those methods, but you're wasting valuable work time waiting for me to return from the event, which is further expanded when I am far away! Can't you figure out a way to stop bothering me?"

And so, Peter decided that even though interfaces were useful for many things, when it came to events, their granularity was not fine enough. He wished to be able to notify interested parties only of the events that matched their hearts' desires. Toward that end, Peter decided to break the methods out of the interface into separate delegate functions, each of which acted like a little tiny interface of one method each:

 
 Delegate Sub WorkStarted() Delegate Sub WorkProgressing() Delegate Function WorkCompleted() As Integer Class Worker     Public started As WorkStarted     Public progressing As WorkProgressing     Public completed As WorkCompleted     Public Sub DoWork()         Console.WriteLine("Worker: work started")         If Not (started Is Nothing) Then started()         Console.WriteLine("Worker: work progressing")         If Not (progressing Is Nothing) Then progressing()         Console.WriteLine("Worker: work completed")         If Not (completed Is Nothing) Then             Dim grade As Integer = completed()             Console.WriteLine("Worker grade = " & grade.ToString())         End If     End Sub End Class Class Boss     Public Function WorkCompleted() As Integer         Console.WriteLine("Better...")         Return 4 ' out of 10     End Function End Class Class Universe     Shared Sub Main()         Dim peter As Worker = New Worker()         Dim theboss As Boss = New Boss()         ' NOTE: We've replaced the Advise method with         ' the assignment operation         peter.completed = New WorkCompleted(AddressOf _ theboss.WorkCompleted)         peter.DoWork()         Console.WriteLine("Main: worker completed work")         Console.ReadLine()     End Sub End Class 

Static Listeners

Delegates accomplished the goal of not bothering Peter's boss with events that he didn't want, but still Peter had not managed to get the universe on his list of subscribers. Since the universe is an all-compassing entity, it didn't seem right to hook delegates to instance members (imagine how many resources multiple instances of the universe would need...). Instead, Peter needed to hook delegates to static members , which delegates support fully:

 
 Class Universe     Shared Sub WorkerStartedWork()         Console.WriteLine("Universe notices worker starting work")     End Sub     Shared Function WorkerCompletedWork() As Integer         Console.WriteLine("Universe pleased with worker's work")         Return 7     End Function     Shared Sub Main()         Dim peter As Worker = New Worker()         Dim theboss As Boss = New Boss()         ' NOTE: use of the assignment operator is *NOT* good         ' practice in the following three lines of code.         ' Keep reading for the right way to add a delegate.         peter.completed = New WorkCompleted(AddressOf _ theboss.WorkCompleted)         peter.started = New WorkStarted(AddressOf _ Universe.WorkerStartedWork)         peter.completed = New WorkCompleted(AddressOf _ Universe.WorkerCompletedWork)         peter.DoWork()         Console.WriteLine("Main: worker completed work")         Console.ReadLine()     End Sub End Class 


Windows Forms Programming in Visual Basic .NET
Windows Forms Programming in Visual Basic .NET
ISBN: 0321125193
EAN: 2147483647
Year: 2003
Pages: 139

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net