Click here to Skip to main content
11,501,561 members (74,856 online)
Click here to Skip to main content

Implementing Observer Pattern in VB.NET

, 1 Jan 2004 75.2K 365 28
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... Pin
schmig6-Jan-04 2:16
memberschmig6-Jan-04 2:16 
GeneralRe: Just curious... Pin
Serge Lobko-Lobanovsky6-Jan-04 3:50
memberSerge Lobko-Lobanovsky6-Jan-04 3:50 
GeneralRe: Just curious... Pin
schmig6-Jan-04 4:01
memberschmig6-Jan-04 4:01 
GeneralRe: Just curious... Pin
Serge Lobko-Lobanovsky6-Jan-04 4:27
memberSerge Lobko-Lobanovsky6-Jan-04 4:27 
GeneralRe: Just curious... Pin
schmig6-Jan-04 4:37
memberschmig6-Jan-04 4:37 
GeneralRe: Just curious... Pin
Serge Lobko-Lobanovsky6-Jan-04 5:04
memberSerge Lobko-Lobanovsky6-Jan-04 5:04 
GeneralRe: Just curious... Pin
bsherwin6-Jan-04 14:53
memberbsherwin6-Jan-04 14:53 
GeneralRe: Just curious... Pin
Serge Lobko-Lobanovsky6-Jan-04 22:52
memberSerge Lobko-Lobanovsky6-Jan-04 22:52 
GeneralRe: Just curious... Pin
BVandenbon22-Aug-07 3:38
memberBVandenbon22-Aug-07 3:38 
I completely agree that it's a matter of taste.

On the other hand I would say it's becoming an anti-pattern to blindly follow the original book of Design Patterns as published 12 years ago. There was no such thing as delegates in those days. In fact Java doesn't support delegates neither does it? (unless that has changed).

What I'm trying to say is: take for example the Decorator pattern. The solution which was presented in the book was great in those days. But today we have an is-operator and a typeof-operator. If you implement the pattern as in the book it kind of ruins the beauty of these 2 statements cause the pattern created an artificial inheritance relation (at runtime) which does not support these real-inheritance based statements. I just want to point out that also this is a conflict or inconsistency. (Other patterns in danger) I'm not saying the Decorator pattern or its solution have become useless. But I'm saying there have to be done some adaptions to secure its beauty. (On top of that: It's too bad that the is- and sizeof-operators cannot be overriden, that would have been a nice solution. Instead maybe Reflection or even better, Generics can give us a hand. Confused | :confused: )

Same goes for the Observer Pattern, remember that there were no events or delegates in languages such as Java. But these days that has changed and let's face it if we start consequently using the Observer Pattern, then in essence every single event is in fact an implementation of the observer pattern, namely an object informing a collection of other objects about a change of state. So, you end up with the .NET framework which uses events while your own code doesn't need it. That's an inconsistency. In other words: implementing the observer pattern in the classic way is an anti-pattern imho.

visit my website at http://antwars.blogspot.com
GeneralRe: Just curious... Pin
displaced16-Apr-08 11:53
memberdisplaced16-Apr-08 11:53 

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 | Terms of Use | Mobile
Web04 | 2.8.150520.1 | Last Updated 2 Jan 2004
Article Copyright 2004 by Serge Lobko-Lobanovsky
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid