Observer Pattern
From REALbasicWiki
Contents |
[edit] Intention
An Observer Pattern defines a one-to-many relationship between a set of objects. When the state of one object changes, all of its dependents are notified.
[edit] Class-Diagram
[edit] Example
The following example shows the Observer Pattern in REALbasic. It was inspired by an example in the book Head First Design Patterns from O'Reilly. Although the examples there are coded in JAVA it is a very good book for RB-programmers too.
Imagine we have a weatherstation that produces data for electronic weather-devices. Each time the weather-conditions change we want our devices to update automatically. To achieve this we implement the Observer Pattern.
First of all we define the Subject-Interface with its three methods notifyObservers(), registerObserver(), removeObserver() The registerObserver-method lets a new Observer register to the Subject. In the case the Observer doesn't want to get notified any longer it needs a way to unregister from the Subject. This is done via the removeObserver-method. When the state of the Subject changes and it wants its Observers to know about that the notifyObservers-method is called that signals all Observers that the Subject has changed its state. If the Observers react to this notification or not depends on themselves.
Interface Subject
Sub notifyObservers()
End Sub
Sub registerObserver(o as Observer)
End Sub
Sub removeObserver(o as Observer)
End Sub
End Interface
Then we define the Observer-Interface. Each object that wants to be notified of any changes of the Subject has to register to it. When the Subjects method notifyObservers is called, the Subject calls the method update() for every Observer it has in its internal list.
Interface Observer
Sub update(t as double, h as double, p as double)
End Sub
End Interface
Now lets take a look on our Subject. For our example the Subject is a class that provides data about weatherconditions. This class has three weather-related properties: humidity, pressure and temperature. It also has an array of type Observer in which all its observers are stored. Each time a new Observer registers via the registerObserver() method, its reference is added to the observers-array. When the measurements change the the WeatherData class informs its Observers that it has changed its state.
Class WeatherData Implements Subject
Sub measurementsChanged()
notifyObservers
End Sub
Sub notifyObservers()
for each o as Observer in observers
o.update(temperature, humidity, pressure)
next
End Sub
Sub registerObserver(o as Observer)
observers.Append o
End Sub
Sub removeObserver(o as Observer)
observers.Remove observers.IndexOf(o)
End Sub
Sub setMeasurements(t as double, h as double, p as double)
self.temperature = t
self.humidity = h
self.pressure = p
measurementsChanged
End Sub
Private humidity As double
Private observers() As Observer
Private pressure As double
Private temperature As double
End Class
Lets create a device that makes use of the data provided by Weatherdata. What about a display that shows us the current weather conditions?
Class CurrentConditionsDisplay Implements Observer
Sub Constructor(s as Subject)
self.weatherData = s
weatherData.registerObserver(self)
End Sub
Sub display()
Msgbox "Current conditions: " + str(temperature) + "F degrees and " + _
str(humidity) + "% humidity"
End Sub
Sub update(t as double, h as double, p as double)
self.temperature = t
self.humidity = h
display
End Sub
Private humidity As double
Private temperature As double
Private weatherData As Subject
End Class
As you can see the CurrentConditionsDisplay implements the update() method from the Observer-interface. Each time the Subjects notifyObservers()-method is called this method will be started.
What about a second observer? Hmmm... lets create a statistic-device that stores weather-data for analysis.
Class StatisticsDisplay Implements Observer
Sub Constructor(s as Subject)
self.weatherData = s
weatherData.registerObserver(self)
End Sub
Sub display()
dim t as string = "Statistics" + endofline + _
"Temperature/Humidity/Pressure" + endofline
for i as integer = 0 to ubound(temperature)
t = t + str(temperature(i)) + "/" + str(humidity(i)) + "/" + str(pressure(i)) _
+ endofline
next
msgbox t
End Sub
Sub update(t as double, h as double, p as double)
self.temperature.Append t
self.humidity.Append h
self.pressure.Append p
display
End Sub
Private humidity() As double
Private pressure() As double
Private temperature() As double
Private weatherData As Subject
End Class
Lets try it out:
dim weatherData as new WeatherData
dim currentDisplay as new CurrentConditionsDisplay(WeatherData)
dim statisticsDisplay as new StatisticsDisplay(WeatherData)
weatherData.setMeasurements(80, 65, 30.4)
weatherData.setMeasurements(82, 70, 29.2)
weatherData.setMeasurements(78, 90, 29.3)
Each time the setMeasurement()-method is called each observer is notified and will fire a messagebox.
[edit] External resources
http://en.wikipedia.org/wiki/Observer_pattern
For more information about the Unified Modeling Language that was used to describe the classes please visit these links:
http://www.holub.com/goodies/uml/index.html

