Click here to Skip to main content
Click here to Skip to main content

Implementing Observer Pattern in VB.NET

, 1 Jan 2004
Rate this:
Please Sign up or sign in to vote.
This article shows an easy way of implementing the Observer pattern in VB.NET

Observer pattern demystified

The Observer pattern is useful when you need to present data in several different forms at once. The Observer is intended to provide you with a means to define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. The object containing the data is separated from the objects that display the data and the display objects observe changes in that data.

There are basically two different types of objects: a Subject and an Observer. The Subject corresponds to the data object whose state you want to track. The Observer is the object that is interested in changes in the Subject's data. To set up the pattern, Subject classes implement a method for registering Observers and for attaching and detaching them from a collection object.

You also need a Notify(...) method to notify all registered Observers when the data has changed. For Observers, you define a custom abstract Observer class to provide clients with a uniform interface, and subclass the implementation details.

Base Implementation

Firstly, we define a public interface called Observer:

Public Interface Observer
  Sub Update(ByVal subj As Object)
End Interface

All our observers (i.e. objects that will be interested in data changes) will have to implement this interface.

Then we define an abstract (MustInherit in VB.NET) class called Subject. This is the base class for all objects whose state we are going to watch.

Public MustInherit Class Subject

A collection where we want our observers to be stored.

Private _observers As New ArrayList()

Methods for adding and removing observers

  Public Sub AddObserver(ByRef ob As Observer)
    _observers.Add(ob)
  End Sub
  
  Public Sub RemoveObserver(ByRef ob As Observer)
    _observers.Remove(ob)
  End Sub

And at last, a public method that will notify all our observers that subject’s state has changed.

  Public Sub Notify()
    Dim ob As Observer
 
    For Each ob In _observers
      ob.Update(Me)
    Next
  End Sub
End Class

We are through with the abstract part of the implementation.

Live Example

We will implement 3 classes (one of them is only for convenience). First one is Broker:

' Class Broker
' one of the model's participants
 
Public Class Broker
  Private _name As String
  Private _balance As Decimal
  Private _acc As New BrokerAccount(Me)
 
  Public ReadOnly Property Account() As BrokerAccount
    Get
      Return _acc
    End Get
  End Property
  Public Sub New()
 
  End Sub
 
  Public Property Name() As String
    Get
      Return _name
    End Get
    Set(ByVal Value As String)
      _name = Value
    End Set
  End Property
 
  Public Property Balance() As Decimal
    Get
      Return _balance
    End Get
    Set(ByVal Value As Decimal)
      _balance = Value
    End Set
  End Property
End Class 'Broker

Second one is BrokerAccount – a class responsible for changing Broker’s balance.

Public Class BrokerAccount
  Inherits Subject
  Private _br As Broker
 
  Public Class InvalidBalanceException
    Inherits Exception
 
    Public Sub New()
      MyBase.New("Broker balance is less than debited amount!")
    End Sub
  End Class
 
  Public Sub New(ByRef br As Broker)
    _br = br
  End Sub
 
  Public Sub Credit(ByVal adAmount As Decimal)
    _br.Balance += adAmount
    MyBase.Notify()
  End Sub
 
  Public Sub Debit(ByVal adAmount As Decimal)
    If _br.Balance - adAmount < 0 Then
      Throw New InvalidBalanceException()
    Else
      _br.Balance -= adAmount
      MyBase.Notify()
    End If
  End Sub
End Class 'BrokerAccount

And a helper class – collection of Broker objects.

Public Class BrokerCollection
  Inherits ArrayList
 
  Default Public Overrides Property Item(ByVal index As Integer) As Object
    Get
      Return MyBase.Item(index)
    End Get
    Set(ByVal Value As Object)
      If Not TypeOf Value Is Broker Then
        Throw New Exception("Can't hold objects of other than Broker type")
      Else
        MyBase.Item(index) = Value
      End If
    End Set
  End Property
 
  Public Overrides Function Add(ByVal value As Object) As Integer
    If Not TypeOf value Is Broker Then
      Throw New Exception("Can't hold objects of other than Broker type")
    Else
      Return MyBase.Add(value)
    End If
  End Function
End Class

The provided sample (MV_Form) gives you a quick overview on how to use this pattern in a Windows Forms application:

Public Class Form1
  Inherits System.Windows.Forms.Form
  Implements MV_Objects.Observer

Form_Load event: Here we initialize a ListView control that holds the list of 10 brokers. Each list view is associated with a Broker object through its Tag property (very useful one indeed Smile | :) )

   For i = 1 To 10
      br = New Broker()
      br.Name = "broker " & i
      br.Account.AddObserver(Me)
 
      itm = New ListViewItem(New String() {br.Name, br.Balance})
      itm.Tag = br
 
      lvBr.Items.Add(itm)
      _brcol.Add(br)
    Next

The following sub implements Update method of the Observer interface. It finds the entry which is associated with a certain broker in the ListView and updates the balance column.

Public Sub UpdateBrokers(ByVal subj As Object) _ 
             Implements MV_Objects.Observer.Update
    Dim br As Broker, itm As ListViewItem
 
    For Each itm In lvBr.Items
      br = itm.Tag
 
      If br.Account Is subj Then
        itm.SubItems(1).Text = br.Balance
      End If
    Next
  End Sub

Also there are 2 buttons and a text box on the form. Their implementation is trivial and not presented in the article for the sake of being concrete.

The End

That’s it! Run the attached sample application to see how it works. You can place a breakpoint on methods Credit and Debit of the BrokerAccount class and step through with a debugger. It’s really a simple but powerful pattern which can used for several more purposes. You are welcome to mention them in the forum Smile | :)

One more thing that can be added to this small project is putting each update procedure in a separate thread. It’s OK when the number of objects being watched is small, but fails on other cases. Any hints on this problem (when the number of objects is more than 50,000) will be really appreciated.

Acknowledgements

This article is based on the work by James Maioriello, Ph.D., where he describes basic design patterns. Sorry, I don’t remember where I got it from, but anyway, I did acknowledge it Smile | :)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Serge Lobko-Lobanovsky
Web Developer
Belarus Belarus
I work for Logic Software (http://www.logicsoftware.net) as a lead .NET developer/architect.

Comments and Discussions

 
GeneralJust curious... Pinmemberschmig6-Jan-04 2:16 
GeneralRe: Just curious... PinmemberSerge Lobko-Lobanovsky6-Jan-04 3:50 
GeneralRe: Just curious... Pinmemberschmig6-Jan-04 4:01 
GeneralRe: Just curious... PinmemberSerge Lobko-Lobanovsky6-Jan-04 4:27 
GeneralRe: Just curious... Pinmemberschmig6-Jan-04 4:37 
But even with your implementation of the Observer pattern, the UI object still needs to know about, and make a call to, the leaf objects in order to register itself as an observer...correct?
 
You obviously can't declare the leaf objects using WithEvents to wire events up automatically, but I'm not sure how making AddObserver/RemoveObserver calls through your Subject interface is any different than the UI using AddHandler/RemoveHandler to register itself as an observer through the event delegate for the leaf objects. You don't need to propogate the events up through the object hierarchy in order to have the UI handle them, since you no longer need to declare an object explicitly WithEvents in order to receive notifications from the event delgate.
 
I'm not trying to be a pain in a$$ about this, honestly Smile | :) But the pros/cons of using delegates vs. some of my own Observer implementations is something I've been looking at recently, and I've yet to figure out the benefits of using my own code (unless you need additional functionality that's outside the scope of the pattern, that is).
 
- J
GeneralRe: Just curious... PinmemberSerge Lobko-Lobanovsky6-Jan-04 5:04 
GeneralRe: Just curious... Pinmemberbsherwin6-Jan-04 14:53 
GeneralRe: Just curious... PinmemberSerge Lobko-Lobanovsky6-Jan-04 22:52 
GeneralRe: Just curious... PinmemberBVandenbon22-Aug-07 3:38 
GeneralRe: Just curious... Pinmemberdisplaced16-Apr-08 11:53 
GeneralUm... Pinmemberobelisk292-Jan-04 16:48 
GeneralRe: Um... PinmemberSerge Lobko-Lobanovsky2-Jan-04 23:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140821.2 | Last Updated 2 Jan 2004
Article Copyright 2004 by Serge Lobko-Lobanovsky
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid