Design patterns – Part 6: Observer pattern
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
April 8th, 2009 at 22:42
After reading through this article, I just feel that I need more information on the topic. Can you suggest some resources ?
April 8th, 2009 at 23:27
There are many great web sites and books on design patterns.
Books:
– Head First Design Patterns was definitely the one I enjoyed most and would recommend it for beginners
– Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley Professional Computing Series) is a classic and a must read for experienced developer
– More books on design patterns
Web sites:
– Wikipedia, as always, has great articles
– Design patterns in C# contains examples of several most used patterns and explains it on examples.
– More on design patterns
April 9th, 2009 at 07:49
FANTASTIC!
April 11th, 2009 at 19:26
I like the info and will be linking back to you from my site. Also great looking site I wish I had one like this.
November 17th, 2012 at 14:49
I wrote an OO MVC lotuscript framwork
While I read your post, I’ll probably found a answers to a majore issue I had.
Observers listen only some kind of event. Those events have various parameters.
Solution could be a class DOOF_Event combined to IsA function and a factory.
December 27th, 2013 at 18:54
This serie about design-patterns in Lotusscript is really cool. Thank you for sharing it.