Create a Custom Application Block That Decouples Your Code

A while back, I worked on a client application where I was significantly responsible for the components. The application was written in Delphi and the components were installed into the toolbox. I returned to the client after a few days off and discovered a huge problem. Some other developers had sent messages from the components to the presentation layer by adding references to the GUI forms in the component layer. Can you tell what went wrong?

If a component or any kind of middleware refers to the presentation layer, that presentation layer goes wherever the components go. This kills reuse—kills it dead in the water. Building an application is hard enough without having to drag all of your old applications along for the ride.

So, about ten years ago I devised a simple way to send information around an application without creating circular references between layers. I called the technique broadcaster and listener, because I modeled it after the notion of radio stations and listeners: A radio station broadcasts without any specific knowledge of or action towards the listeners who tune in.

Many of you will recognize this as an implementation of the Observer behavior pattern (in other words, the publish-subscribe implementation of Observer). It successfully separates internal messaging within an application. The gang of four (GoF) published it first and will forever get the credit, but this implementation—I call it the Radio pattern—is easy for any developer to create and use. (For more information on the Observer behavior pattern, refer to Design Patterns: Elements of Reusable Object Oriented Software by Erich Gamma and company from Addison Wesley.)

I refer to the three combined elements of the implementation (the listener, audience, and broadcaster classes) as the Radio Application Block (RAB). You can incorporate and use it like any other of the readily available application blocks, such as DAAB or EMAB. (If you are unfamiliar with these, just Google them: DAAB site://www.microsoft.com.)

This article demonstrates how you can implement the Radio pattern to keep your application code loosely coupled.

Defining the Listener

Many languages in .NET do not support multiple inheritance. Thus, because I am not using events and don't want to use what may be only one inheritance slot, I elected to implement the listener by using an interface.

The objective of the listener is to tune in and listen for messages. These goals can be captured in a simple interface with a Boolean that indicates a tuned-in state and a method that receives messages. Alternatively, strings and an object would work too. Listing 1 contains the implementation of the IListener interface. (An I prefix is used by convention.)

Listing 1: An Implementation of the IListener Interface

Public Interface IListener

   ReadOnly Property Listening() As Boolean
   Sub Listen(ByVal message As String)

End Interface

You could add methods to accept an object, a DateTime, or some additional information, but to make the Radio pattern easier to use, leave it to consumers to format the message into a string.

Defining the Audience

Audience simply refers to any listeners. A listener is any class that implements IListener and adds itself to the listener's collection. I used a strongly typed collection of IListener to represent the audience. I have covered typed collections several times in previous articles, so I will just provide that code in Listing 2.

Listing 2: An Implementation of a Typed Collection of IListener

Imports System.Collections

Public Class ListenerCollection
   Inherits CollectionBase

   Default Public Property Item(ByVal index As Integer) As IListener
      Get
         Return CType(List(index), IListener)
      End Get
      Set(ByVal Value As IListener)
         List(index) = Value
      End Set
   End Property

   Public Function Add(ByVal Value As IListener) As Integer
      Return List.Add(Value)
   End Function

   Public Sub Remove(ByVal Value As IListener)
      If (list.Contains(Value)) Then
         list.Remove(Value)
      End If
   End Sub

End Class

Create a Custom Application Block That Decouples Your Code

Turning on the Radio

Next, you need a class that represents the radio station (or broadcaster). I used the Singleton pattern to ensure there was only one broadcaster. Although you could implement multiple radio stations, using just one keeps things simple.

The Broadcaster has only shared public methods and an internal reference to the typed ListenerCollection. To begin receiving messages, implement IListener and invoke Broadcaster.Add(me). To stop listening, invoke Broadcaster.Remove(me). Anyone can send messages by calling Broadcaster.Broadcast.

Broadcasting works simply by iterating through the list of listeners. If a listener's Listening property returns True, that listener's Listen method is called. (This is pretty much how multicast delegates work, too.) Listing 3 contains the complete implementation of the Broadcaster class.

Listing 3: The Broadcaster Class

Public Class Broadcaster

   Private list As ListenerCollection
   Private Shared this As Broadcaster = Nothing

   Protected Sub New()
      list = New ListenerCollection
   End Sub

   Protected Shared ReadOnly Property Instance() As Broadcaster
      Get
         If (this Is Nothing) Then this = New Broadcaster
         Return this
      End Get
   End Property

   Public Shared Function Add(ByVal value As IListener) As Integer
      Return Instance.list.Add(value)
   End Function

   Public Shared Sub Remove(ByVal value As IListener)
      Instance.list.Remove(value)
   End Sub

   Public Shared Sub Broadcast(ByVal message As String)
      Dim listener As IListener
      For Each listener In Instance.list
         Try
            If (listener.Listening) Then
               listener.Listen(message)
            End If
         Catch ex As Exception
            Instance.list.Remove(listener)
         End Try
      Next
   End Sub
End Class

To complete the application block, use the sn.exe utility (sn –k) to create a strong name if you want the class library to be installed in the GAC.

Finally, use the setup wizard to create a .msi file. (I won't explain how to use the wizard; I know you can figure that out.)

That's it! Distribute the .msi file and you have implemented your first application block.

Testing the Radio Application Block

To test the radio application block, use the following steps:

  1. Create a new Windows Forms application.
  2. Indicate that the main form implements Ilistener.
  3. Make Listening return True.
  4. Add a statusbar to the main form and define Listen to write to the StatusBar.Text property.
  5. In Form_Load, call Broadcaster.Add(Me) and then call Broadcaster.Broadcast("My first application block");.

That's all there is to it. When you run the Windows Forms application, the text should appear in the StatusBar. The key here is that the Radio Application Block is reusable and has no specific knowledge of any of the listeners' types; that is, the RAB can go anywhere without dragging your applications along with it. Listing 4 contains an example Windows Form (without the automatically generated code).

Listing 4: A Sample Test Windows Forms Form

Imports ApplicationBlock.Radio

Public Class Form1
   Inherits System.Windows.Forms.Form
   Implements IListener


#Region [ Windows Form Designer generated code ]

   Private Sub Form1_Load(ByVal sender As System.Object, _
      ByVal e As System.EventArgs) Handles MyBase.Load
         Broadcaster.Add(Me)
         Broadcaster.Broadcast("This is my first application block")
   End Sub

   Public ReadOnly Property LIstening() As Boolean _
      Implements IListener.Listening
         Get
            Return True
          End Get
   End Property

   Public Sub Listen(ByVal message As String) _
      Implements IListener.Listen
        StatusBar1.Text = message
   End Sub
End Class

Loosely Coupled Code

The Observer pattern and the Radio Application Block, which represents an implementation of the Observer pattern, are perfect examples of loosely coupled code. If you don't get it, that's okay. It's important that you try to get it, however.

If someone you are working with poo-poos it as overly complex, then go ahead and feel superior. At least in this instance, you are.

About the Author

Paul Kimmel is the VB Today columnist for www.codeguru.com and has written several books on object-oriented programming and .NET. Check out his upcoming book UML DeMystified from McGraw-Hill/Osborne (Spring 2005) and Expert One-on-One Visual Studio 2005 from Wrox (Fall 2005). Paul is also the founder and chief architect for Software Conceptions, Inc., founded 1990. He is available to help design and build software worldwide. You may contact him for consulting opportunities or technology questions at pkimmel@softconcepts.com.

If you are interested in joining, sponsoring a meeting, or posting a job, check out www.glugnet.org, the Web page of the Greater Lansing area Users Group for .NET.

Copyright © 2005 by Paul T. Kimmel. All Rights Reserved.



Comments

  • There are no comments yet. Be the first to comment!

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

  • The proliferation of cloud computing options has begun to change the way storage is thought about, procured, and used. IT managers and departments need to think through how cloud options might fit into and complement their onsite data infrastructures. This white paper explains cloud storage and backup, providing advice about the tools and best practices for its implementation and use. Read this white paper for some useful takeaways about how to take advantage of cloud storage for high availability, backup and …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds