Observer Pattern in Go
This is the second chapter of Head First Design Patterns book. Though the book has code snippets in Java, my attempt here is to implement the problem discussed in Go. Without further ado, let’s understand the use-case.
The problem statement
We are told to design a weather monitoring application. It consists of 3 sections
- Weather station : to record humidity, temperature and pressure
- Weather data : tracks data from the weather station and forwards it to the displays
- various display elements :
- current conditions,
- weather statistics,
- a simple forecast, and
- a heat index calculator
Thought process
- Weather station should collect the data, and notify the changes to the various devices.
- In design terminology, the weather station is the
subject
, and the display devices are theobservers
. - Weather station is the single owner of the data, devices are dependent on it for any updates.
- The common analogy often used here is that of publisher-consumer models.
Suppose you want to avail a newspaper subscription. Once you register for it, you get a daily copy. But the moment, your subscription ends, you no longer receive it.
- For our use-case, a loosely coupled system provided by the Observer Pattern, will greatly benefit us.
- The station is responsible in sending the collected data, it should not be bothered about how the observing devices use it.
- Suppose a better index (e.g. WBGT) comes up and heat index becomes irrelevant, we should be able to freely add the new device, and remove the heat index device.
- We would not want to modify the code for the subject, when the new observer (WBGT device) comes in.
- Changes to either the subject or the observer should have no impact on each other.
- Similarly, both should be reusable and independent to each other.
UML Class Diagram
In the code, I have renamed a few things.
CurrentConditions
is nowCurrCondDisplay
StatisticsDisplay
is nowStatDisplay
The Code
The output of the above code is
Current conditions: 80.0F degrees and 65.0% humidity.
Avg/Max/Min temperature = 80.0/80.0/80.0
Forecast : Improving weather on the way!
Heat index is 82.955345Current conditions: 82.0F degrees and 70.0% humidity.
Avg/Max/Min temperature = 81.0/82.0/80.0
Forecast : Watch out for cooler, rainy weather!
Heat index is 86.901260Current conditions: 78.0F degrees and 90.0% humidity.
Avg/Max/Min temperature = 80.0/82.0/78.0
Forecast : More of the same.
The complete code implementation can be found in my Github repository.
Language specifics
Note: Go channels which are idiomatic way of handling data in concurrent code (routines) can be applicable to this use-case. Perhaps, I’ll cover that in another article.
I found two ways of handling multiple inheritance.
- Composition of smaller interfaces to make a single interface.
type displayerObserver interface {
Displayer
Observer
}
2. Type assertion of structs.
...
func (sd *StatDisplay) update(temp float32, humidity float32, pressure float32) {
...
var d Displayer = sd
d.display()
...
}
// check statDisplay.go file for more detail
Takeaways
The book defines,
The Observer Pattern defines a one-to-many dependency between objects so that when one object changes state, all of its dependents are notified and updated automatically.
Some interesting design principles arise
- Identify the aspects of your application that vary and separate them out from what stays the same.
- Program to an interface, not an implementation.
- Favour composition over inheritance.
- Strive for loosely coupled designs between objects that interact.