Login | Register   
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Design for Extensibility : Page 7

Build extensibility and flexibility into your applications to simplify maintenance and accommodate changes.


advertisement
Extensibility with Multiple Modules
It gets a little more complicated when you have more than one module tapping into this event. The code that executes the Invoke method will fire all the modules wired to the CheckDataSource events, one after the other. Remember, this happens because the initialization routine sends and receives the same ModuleEvents object to each module's Initialize method. Now think of the order of events here (no pun intended). If I have three modules that tap into this event, each checking the data source for something different, the first one that gets executed will receive the initial value of the Cancel property, which is false. If the code in any module changes that value, the next module that the code executes will contain that new value, because the Invoke method gets called once with the one EventArgs object. This means that it is up to me to code the module event to check the value of e.Cancel before executing any of the event logic. With that in mind, a properly written module that taps into the CheckDataSource event should look like this:

' In VB: Private Sub events_CheckDataSource( _ ByVal e As CheckDataSourceEventArgs) If Not e.Cancel Then If e.Source.ToUpper(). _ IndexOf("BAD") _> -1 Then e.Cancel = True End If End If End Sub // In C#: void events_CheckDataSource( CheckDataSourceEventArgs e) { if (!e.Cancel) { if (e.Source.ToUpper(). IndexOf("BAD") > -1) e.Cancel = true; } }

If you code all the modules this way, as soon as any module that intercepts this event sets the e.Cancel property to true, no other module's CheckDataSource event will process any code.

Another choice for this kind of logic is probably a bit safer. The previous examples put the responsibility of check for cancellation in the module's code. But the same developer may not write all your modules, so it may not be reliable to do that. By writing a little more code on the client, you can iterate through the delegate invocation list (in this case, CheckDataSource) and fire each one separately, checking the value of the Cancel property after each one and deciding whether to continue.

' In VB: Dim o_InvocationList() As _ [Delegate] = o_FilterEvents. _ CheckDataSource.GetInvocationList() For Each o_Filter As AcmeModuleDelegate( _ Of CheckDataSourceEventArgs) In o_InvocationList If o_Filter IsNot Nothing Then Dim o_EventArgs As New _ CheckDataSourceEventArgs( s_Source) o_Filter.Invoke(o_EventArgs) If o_EventArgs.Cancel Then b_Cancel = True Exit For End If End If Next // In C#: Delegate[] o_InvocationList = o_FilterEvents.CheckDataSource. GetInvocationList(); foreach ( AcmeModuleDelegate <CheckDataSourceEventArgs> o_Filter in o_InvocationList) { if (o_Filter != null) { CheckDataSourceEventArgs o_EventArgs = New CheckDataSourceEventArgs( s_Source); o_Filter.Invoke(o_EventArgs); if (o_EventArgs.Cancel) { b_Cancel = true; break; } } }

Using this technique, as soon as one module sets its e.Cancel property to true, the code breaks out of the loop and stops further processing. In both techniques, the b_Cancel variable determines whether processing should continue, but the responsibility for making the check differs.

You can insert additional extensibility points in either of the two methods: the one that calls all module events in one Invoke execution or the one that iterates through the invocation list of the corresponding delegate and invokes one event at a time.

Extensibility modules are a great way to put multiple points of extensibility in your client and, at the same time, centralize how you write the extensibility plug-ins. You can choose to develop a class for each event you want to subscribe to, or you can group several together. If you choose the latter, you should do so because the interception code you're placing into the various events is somehow logically related from one event to another. An example of this would be in writing a Profanity Filter. You might want such a filter to check for profanity at different points in your application. For example, in the scenario you've seen, you could check for profanity at both the CheckDataSource point or at one called PreProcessData by writing one module class that taps into both of these events. The events will still be called from their appropriate extensibility points within the client, but they will be housed in one class, grouping them together logically. Listing 5 shows the entire code for such a module.

These patterns can help you design and code applications that are easier and more elegant to enhance or modify. They also introduce a style of programming that's based on the ability to interchange functionality easily. However, don't feel that you have to spend too much time on deciding where to insert points of extensibility in your application—just keep it all in mind. As you design and develop applications, more than likely you will find extensibility points that just snap out at you. Try to resist abstracting at the beginning of the design process, and don't be afraid to refactor into it later; but beware—after you get the hang of using these patterns, you will be addicted.

You can download the code for this article from the User Group Downloads section of the link. You can find some basic references in the "Additional References" sidebar. You can also watch a DNR-TV episode on this entire subject.


Miguel A. Castro is President of InfoTek Consulting Group, Inc., a professional consulting firm that specializes in architecting, designing, and developing solutions using Microsoft .NET technologies. His VB background goes all the way back to 1.0. Miguel's focus for the last couple of years has been the .NET Framework and languages; he is fluent in both VB .NET and C#. His programming experience goes back 20 years when he started on TRS-80s, Apple IIs, and Atari 800 computers. Miguel lives in Lincoln Park, New Jersey with his wife Elena and his daughter Victoria.
Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap