September 16, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

.NET Remoting and Event Handling in VB .NET, Part 3

  • March 7, 2005
  • By Paul Kimmel
  • Send Email »
  • More Articles »

Using the Factory Method Creational Pattern

There are three categories of patterns: behavioral, creational, and structural. Behavioral patterns define how objects interact; creational patterns define how objects are created; and structural patterns deal with class composition. The factory method is a creational pattern.

The factory method pattern manages the creation of related objects based on some criteria or a compound creational process. For example, the factory method helps when you need to perform several operations to create an object and ensure its proper initialization. In this example, for criteria like the text the user enters and the value that text represents, the factory method can contain the logic in one place to figure out which object to create. As Listing 1 shows, this example checks every possible command to see whether the command-line arguments represent a command by calling the static (Shared) Wants method on each command class. If it doesn't find a suitable command, an instance of the NullCommand is returned.

A final benefit is that no matter how many commands are ultimately created, the code for instantiating that command is modified in one place: the CommandFactory.Create method. Getting an instance of a command object looks the same throughout your application.

Using the Singleton Creational Pattern

Another creational pattern is the singleton pattern. Singleton's job is to ensure that only one instance of an object exists forever. It easily accomplishes this by using a non-public modifier on the constructor (Sub New) and a static method to access an instance of that class. As a static method, it can check to see whether an internal instance to the object exists. If the singleton object doesn't exist, the static method—as a member—can access the constructor and create the one and only instance. If the object does exist, the instance is returned.

The chat example uses the singleton pattern to ensure that only one instance of the Client class is created. In the elided example in Listing 2, you can see how the singleton is implemented as described by the private Client.New method and the public, shared, read-only Instance property.

Listing 2: The Singleton Pattern Ensures That Only One Instance of the Client Class Is Created Per Client Application Instance

Public Class Client
    Inherits MarshalByRefObject
    Implements IDisposable

    Private FChatter As Chatter
    Private Shared FClient As Client = Nothing

    Private Sub New()
        RemotingConfiguration.Configure("client.exe.config")
        FChatter = New Chatter
        AddHandler FChatter.MessageEvent, AddressOf OnMessageEvent
    End Sub

    Private Shared ReadOnly Property Instance() As Client
        Get
            If (FClient Is Nothing) Then
                FClient = New Client
            End If
            Return FClient
        End Get
    End Property
//...

Using the Observer Pattern

Programmers run into trouble when they start cross-referencing things like form references. For instance, Form1 creates Form2 so Form1 has a reference to Form2. Form2 wants to update a status bar on Form1, so Form2 in turn has a reference to Form1. All of this criss-crossing of references results in a tightly coupled implementation. The problem is exacerbated when object1 knows about object2 and vice-versa, and one of the objects is a Form and the other is a control that you want to install in the Toolbox or use in another application. Now, your control is aware of a specific form that exists in just one application, which means the first form's assembly is loaded by VS.NET and any other application that uses that control.

Because tightly coupled implementations have lots of problems, events (now called delegates) exist. Delegates are an example of an implementation of the observer pattern, which is another behavioral pattern. The observer pattern is also known as publish and subscribe. It is the publish-subscribe version of the observer pattern, which I originally called broadcaster and listener (or radio pattern) when I discovered it independently seven years ago this month. (I will use the broadcaster and listener metaphor, as I think it works best here.)

The basic idea of radio is that a station sends out a signal. Listeners can tune in and receive the signal and then tune out. The radio station doesn't have to—although it would like to—know who is listening when, and the listeners don't have to know where the station is physically located. The listeners tune in and receive the signal, and multiple listeners can listen at the same time.

In code, this would mean that the sender of a message doesn't have to know who is receiving the message (loose coupling), multiple listeners (a status bar, the event log, or something else) can tune in, and listeners can come and go with impunity.

All of this code can be implemented one time as a typed collection of listeners. The listeners are defined as an interface, and a centralized broadcaster keeps track of listeners and acts as a central repository for messages. Simply send a message to the broadcaster and anything tuned in will be sent a copy of the message. The originator and broadcaster don't care what the listeners do with the message or even who is listening. (Listing 3 defines the IListener interface; Listing 4 defines the ListenerCollection; and Listing 5 defines the Broadcaster.)

Listing 3: The IListener Interface

Public Interface IListener
    ReadOnly Property Listening() As Boolean
    Sub Listen(ByVal message As String)
    Sub Listen(ByVal message As String, ByVal formatter As IFormatter)
End Interface

Listing 4: The Strongly Typed ListenerCollection

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)
        List.Remove(value)
    End Sub

End Class

Listing 5: The Broadcaster Receives and Sends Messages to All Listeners

Public Class Broadcaster

    Private Shared FInstance As Broadcaster = Nothing
    Private listeners As ListenerCollection

    Protected Sub New()
        listeners = New ListenerCollection
    End Sub

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

            Return FInstance
        End Get
    End Property

    Public Shared Function Add(ByVal listener As IListener) As Integer
        Return Instance.listeners.Add(listener)
    End Function

    Public Shared Sub Remove(ByVal listener As IListener)
        Instance.listeners.Remove(listener)
    End Sub

    Public Shared Sub Broadcast(ByVal format As String, _
                                ByVal ParamArray args() As Object)
        Broadcast(String.Format(format, args))
    End Sub

    Public Shared Sub Broadcast(ByVal message As String)
        Broadcast(message, New GenericFormatter)
    End Sub

    Public Shared Sub Broadcast(ByVal message As String, _
                                ByVal formatter As IFormatter)
        Dim listener As IListener
        For Each listener In Instance.listeners
            If (listener.Listening) Then
                listener.Listen(message, formatter)
            End If
        Next
    End Sub

End Class
Note: The Broadcaster uses the singleton pattern to ensure that only one Broadcaster instances exists. This ensures every message and listener go to the same place.

Anything that implements IListener can be added to and removed from the Broadcaster's collection of listeners. When a message arrives from anywhere—because the static method Broadcaster.Broadcast was called—the Broadcaster iterates through every listener in the collection and repeats the message. This means that if a form implements IListener (the Listening property and the Listen methods), then that form can receive the message. It also means any class can listen. The elided class ClientApp in Listing 6 shows how the presentation layer in the chat sample listens for messages from the remote server without ever knowing that they came from the remote server.

Listing 6: Realizing the Radio Pattern in the Console Presentation Layer

Imports Softconcepts.ApplicationBlocks.RadioPattern

Class ClientApp
    Implements IListener

    Public Overloads Sub Listen(ByVal message As String) _
           Implements IListener.Listen
        Console.WriteLine(message)
    End Sub

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

    Public Shared Sub Main()
        With New ClientApp
            .Run()
        End With
    End Sub

    Public Sub Run()
        Broadcaster.Add(Me)

        ProcessCommand("Startup")

        While (True)
            Console.Write("chat>")
            If (ProcessCommand(Console.ReadLine()) = False) _
            Then Exit While
        End While

        ProcessCommand("Shutdown")

        Broadcaster.Remove(Me)
    End Sub

    Public Overloads Sub Listen(ByVal message As String, _
      ByVal formatter _
      As Softconcepts.ApplicationBlocks.RadioPattern.IFormatter) _
      Implements Softconcepts.ApplicationBlocks.RadioPattern.IListener.Listen
        If (message.Equals("chat>")) Then
            Console.Write(message)
        Else
            Console.WriteLine(formatter.ApplyFormatting(message))
        End If
    End Sub
//...




Page 2 of 3



Comment and Contribute

 


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

 

 


Sitemap | Contact Us

Rocket Fuel