One of the most used patterns is also a pattern that hears by the name Observer. What does it do? Well, imagine you have a stock portfolio and you need to notify your investors every time the value of their stock changes. First, your investors need to subscribe to the stock they would like to be notified about. Next, whenever new stock value is published, subscribers are notified. Much like RSS subscription. But what about definition:

The Observer pattern defines a one-to-many dependency between objects so that when one object changes state, all of its dependants are notified and updated automatically.


Fine, but what can I do with that?

We will build an above mentioned example of a stock and it’s investors. First, you will need to create an observer abstract class:

Class CObserver
	m_strName As String

	Property Get ObserverName As String
		ObserverName = Me.m_strName
	End Property

	Sub New (strName As String)
		Me.m_strName = strNAme
	End Sub

	Sub Update()
	End Sub
End Class

As you can see, it contains a name, which will be used as unique id, a constructor, where the name is set and subroutine called Update that will be called when new value of our stock will be set.

Now, that we have an observer, we can create a subject class that will be an abstract class used by our stock.

Class CObserverSubject
	m_oList List As CObserver

	Sub Attach (observer As CObserver)
	  If (Not Iselement (m_oList (observer.ObserverName))) Then
	     Set m_oList (observer.ObserverName) = observer
	  End If
	End Sub

	Sub Detach (observer As CObserver)
	  If (Iselement (m_oList (observer.ObserverName))) Then
	     Erase m_oList (observer.ObserverName)
	  End If
	End Sub

	Sub Notify ()
		Forall observer In m_oList
			Call observer.Update()
		End Forall
	End Sub
End Class

The class contains list of all investors (observers) and operations to add (Attach ()) or remove (Detach ()) them. There is also routine Notify, that will update each and every investor.

Framework is now set. Moving on to concrete classes. First, we will create a concrete subject class called ObserverStock.

Class CObserverStock As CObserverSubject
	m_strName As String
	m_dValue As Double

	Property Get StockName As String
		StockName = Me.m_strName
	End Property

	Property Get Value As Double
		Value = Me.m_dValue
	End Property

	Property Set Value As Double
		Me.m_dValue = Value
		Call Notify()
	End Property

	Sub New (strName As String, dValue As Double)
		Me.m_strName = strName
		Me.m_dValue = dValue
	End Sub
End Class

The class inherits from ObserverSubject class. Also, it has a property for obtaining stock name and properties for obtaining and setting stock value. However, when setting stock value, not only value is set, but there is also a call to Notify method, specified in ObserverSubject class. This will notify all subscribers of new value.

The only thing missing now is observer concrete class called ObserverInvestors.

Class CObserverInvestor As CObserver
	m_Stock As CObserverStock

	Property Get Stock As CObserverStock
		Set Stock = Me.m_Stock
	End Property

	Property Set Stock As CObserverStock
		Set Me.m_Stock = Stock
	End Property

	Sub New (strName As String)
	End Sub

	Sub Update()
		Messagebox Me.m_strName & ": " &_
		m_Stock.StockName & " value is " & m_Stock.Value
	End Sub
End Class

And it is simple enough. It needs a constructor with name as parameter (due to his parent class), a property that ties stock to the class and Update () function that will ideally send an e-mail to investors, but in this case just pops up a message with investor and stock info.

Usage of previous classes

To use previously stated classes, I wrote an agent that will create a stock, add three investors to it, and change value. Then, last observer will be removed from notification list and value will be updated again. When running this agent, you should first get three pop up messages and then only two.

Sub Initialize
	Dim observer As CObserverInvestor
	Dim stock As CObserverStock

	Set stock = New CObserverStock ("MyStock", 120.0)

	Set observer = New CObserverInvestor ("Investor 1")
	Set observer.Stock = stock
	Call stock.Attach (observer)

	Set observer = New CObserverInvestor ("Investor 2")
	Set observer.Stock = stock
	Call stock.Attach (observer)

	Set observer = New CObserverInvestor ("Investor 3")
	Set observer.Stock = stock
	Call stock.Attach (observer)

	stock.Value = 100.0

	Call stock.Detach (observer)
	stock.Value = 102.5
End Sub