The Observer design pattern in .NET, part 1

Today we’ll implement the “classic” Observer design pattern in VB .NET. This is part 1 of a 3 part series; part 2 will discuss transitioning the design pattern to .NET events, and part 3 will discuss some uses of the Observer pattern built into .NET. You can download the Observer design pattern example if you want to see the code in action.

Use the Observer design pattern when:

  • You have a subject of interest whose state may be monitored.
  • Any number of objects might need to monitor the subject.
  • You desire “loose coupling” between the subject and the observers.

How it works

The Observer design pattern works much like a newspaper publisher and its subscribers. In fact, it is sometimes called the Publisher-Subscriber design pattern. In this pattern, you have a Subject object (the publisher) that maintains a collection of any number of observers (the subscribers). It provides methods to add and remove observers from this collection. It also contains a method to notify all observers of some change in state.

Interfaces

In the Observer pattern the publisher would be called the “subject”. The subject has state (in our case, a headline) that it maintains. The subject implements an interface as shown here:

Public Interface IObservable
    Sub Subscribe(ByVal observer As IObserver)
    Sub Unsubscribe(ByVal observer As IObserver)
    Sub NotifySubscribers()
End Interface

It has two methods for tracking the subscription and unsubscription of subscribers, and a method for notifying subscribers of an update to the subject’s state.

In the Observer pattern the subscriber would be called the “observer”, and it implements this interface:

Public Interface IObserver
    Sub Update(ByVal subject As IObservable)
End Interface

When the subject’s NotifySubscribers method is called, it calls the Update() method for every observer that is currently subscribed.

The Subject

Here is an implementation of a class we’ll call SubjectPublisher:

Public Class SubjectPublisher
    Implements IObservable
    Private observers As New List(Of IObserver)
    Private _headline As String = ""
    Public Property Headline() As String
        Get
            Return _headline
        End Get
        Set(ByVal value As String)
            If _headline <> value Then
                _headline = value
                NotifySubscribers()
            End If
        End Set
    End Property
    Private Sub NotifySubscribers() Implements IObservable.NotifySubscribers
        For Each o As IObserver In observers
            o.Update(Me)
        Next
    End Sub
    Public Sub Subscribe(ByVal observer As IObserver) Implements IObservable.Subscribe
        observers.Add(observer)
    End Sub
    Public Sub Unsubscribe(ByVal observer As IObserver) Implements IObservable.Unsubscribe
        While observers.Contains(observer)
            observers.Remove(observer)
        End While
    End Sub
End Class

As you can see it implements the IObservable interface as discussed earlier. In addition, it implements a Headline property. Whenever the Headline changes, it calls the NotifySubscribers method to update the currently subscribed observers.

The Observer

Here is an implementation of a class we’ll call ObserverSubscriber:

Public Class ObserverSubscriber
    Implements IObserver
    Private _headline As String = ""
    Public ReadOnly Property Headline() As String
        Get
            Return _headline
        End Get
    End Property
    Public Sub Update(ByVal subject As IObservable) Implements IObserver.Update
        _headline = CType(subject, SubjectPublisher).Headline
    End Sub
End Class

It implements the IObserver discussed earlier. In addition, it implements a read-only Headline property in order to provide access to the value it collects during Update.

Push vs. Pull

Note that during the call to Update no specific state is sent, only a reference to the subject. We could have implemented Update so that specific state was “pushed” as a parameter. However, the preferred design pattern method is to have the observer “pull” whatever state is necessary from the subject. It could be that every observer needs different parts of the subject’s state.

Observer design pattern in action

Let’s pull the concepts together with a test GUI. Here’s a screenshot of the Observer pattern test GUI.

In this test GUI, there is a section to update the subject with a new headline, and there is a section to subscribe/unsubscribe each of three different observers. You should notice that any observer that has Subscribed? checked will receive a headline update any time the Update button is clicked for the subject. Here’s the code:

Public Class Form1
    Private _subject As New SubjectPublisher
    Private _observer1 As New ObserverSubscriber
    Private _observer2 As New ObserverSubscriber
    Private _observer3 As New ObserverSubscriber
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    End Sub
    Private Sub uxSaveHeadline_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles uxSaveHeadline.Click
        _subject.Headline = uxHeadline.Text
        uxHeadline1.Text = _observer1.Headline
        uxHeadline2.Text = _observer2.Headline
        uxHeadline3.Text = _observer3.Headline
    End Sub
    Private Sub uxSubscribed1_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles uxSubscribed1.CheckedChanged
        If uxSubscribed1.Checked Then
            _subject.Subscribe(_observer1)
        Else
            _subject.Unsubscribe(_observer1)
        End If
    End Sub
    Private Sub uxSubscribed2_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles uxSubscribed2.CheckedChanged
        If uxSubscribed2.Checked Then
            _subject.Subscribe(_observer2)
        Else
            _subject.Unsubscribe(_observer2)
        End If
    End Sub
    Private Sub uxSubscribed3_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles uxSubscribed3.CheckedChanged
        If uxSubscribed3.Checked Then
            _subject.Subscribe(_observer3)
        Else
            _subject.Unsubscribe(_observer3)
        End If
    End Sub
End Class

That’s it for today. Don’t forget to check in later when we talk about the use of .NET events in the observer pattern, and occurrences of the observer pattern built into .NET.

Share and Enjoy: These icons link to social bookmarking sites where readers can share and discover new web pages.
  • bodytext
  • del.icio.us
  • Facebook
  • Google
  • Reddit
  • StumbleUpon
  • Technorati

One Response to “The Observer design pattern in .NET, part 1”

  1. [...] is part 2 in a series about the Observer design pattern in .NET. In part one, we saw how to implement the pattern using the “classical” approach. In this part, [...]

Leave a Reply