Design Patterns: Observer Pattern

I got my eye on you...

Suppose you want to show the user some real-time data. How will your code know when something has changed and it needs to update what it displays? One possibility would be to call the classes to display the information each time something changes. As an example, let's suppose we own a factory with an assembly line. We have some hardware installed on the assembly line that can measure how many boxes of widgets and boxes of gizmos are going out every minute. We'd like to have an application that displays the current production rate of widgets and gizmos well as some statistics for each.

In the code below, take for granted that the hardware already interfaces with the software to call the ProductionRateChanged() method any time the rate changes.

Code Snippet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class FactoryProductionData
{
  public void ProductionRatesChanged()
  {
    //take for granted that these methods work
	var widgetRate = getWidgetRate();
	var gizmoRate = getGizmoRate();

	//these calls actually update the display
	//with latest data
	currentRateDisplay.update(widgetRate, gizmoRate);
	statisticsDisplay.update(widgetRate, gizmoRate);
  }
}

Each time the rate at which widgets and gizmos are produced changes, the ProductionRatesChanged() method is called and the display updates. While this implementation might work, we notice a few things:

  • The ProductionRatesChanged() method will need to be updated for each new display element
  • We're coding to concrete implementations, rather than interfaces
  • There's no way to add/remove display elements at run time
  • We haven't encapsulated the bit of code that changes

Enter...the Observer Pattern.

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.

The authors of Head First Design Patterns use the analogy of a newspaper. You (a subscriber) can tell the newspaper company (the publisher), that you wish to subscribe to their newspaper. Every time there's a new newspaper, you get it. If you wish to unsubscribe, you can. If you want to stay subscribed forever, you can. If others want to subscribe, they can. In design pattern language, you and the others would be the observers. The newspaper company is the subject.

As usual, let's jump straight to the implementation and unpack it from there. First, here are our new interfaces, IObserver and ISubject. We also created an IDisplay interface as well for the various displays to inherit.

Code Snippet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public interface IObserver
{
  void Update(double widgetRate, double gizmoRate);
}

public interface ISubject
{
  void RegisterObserver(IObserver observer);
  void RemoveObserver(IObserver observer);
  void NotifyObservers();
}
 
public interface IDisplayElement
{
  void Display();
}

As expected, the ISubject interface does exactly what you'd hope. It can register new observers to begin getting updates, it can remove observers who no longer wish to receive updates, and it can notify all the observers currently subscribed when there is an update.

Likewise on the IObserver class, the only method it needs should allow for updates. This is the method which will be called on each observer when the subject notifies them.

Our subject, FactoryProductionData can now inherit from ISubject in the new implementation.

Code Snippet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class FactoryProductionData : ISubject
{
  private List<IObserver> observers;
  private double widgetRate;
  private double gizmoRate;

  public FactoryProductionData()
  {
	observers  = new List<IObserver>();
  }

  public void RegisterObserver(IObserver observer)
  {
	observers.Add(observer);
  }

  public void RemoveObserver(IObserver observer)
  {
	observers.Remove(observer);
  }

  public void NotifyObservers()
  {
	foreach (var observer in observers)
	{
	  observer.Update(widgetRate, gizmoRate);
	}
  }

  public void ProductionRatesChanged()
  {
	NotifyObservers();
  }
	
}

The implementations on of the ISubject class on the FactoryProductionData class are exactly what you'd expect them to be. The FactoryProductionData class keeps a list of observers to notify when something changes via the RegisterObserver() and RemoveObserver() methods and updates them via the NotifyObservers() method.

Next we have the implementation of the IObserver interface in the CurrentProductionRatesDisplay class.

Code Snippet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class CurrentProductionRatesDisplay : IObserver, IDisplayElement
{
  private double _widgetRate;
  private double _gizmoRate;
  private ISubject _factoryProductionData;

  public CurrentProductionRatesDisplay(ISubject factoryProductionData)
  {
	_factoryProductionData = factoryProductionData;
	_factoryProductionData.RegisterObserver(this);
  }

  public void Update(double widgetRate, double gizmoRate)
  {
	_widgetRate = widgetRate;
	_gizmoRate = gizmoRate;
	Display();
  }

  public void Display()
  {
	//code here to display _widgetRate and _gizmoRate
  }
}

A few things to notice...first, a default constructor is used to register the CurrentProductionRatesDisplay as an observer with the FactoryProductionData subject. Second, when the NotifyObservers() method of FactoryProductionData is called, it is the Update() method on CurrentProductionRatesDisplay that will be called. It can then call it's own Display() method (inherited from IDisplay) to show the updated information to the user.

For sake of completeness, I'll likewise show what the ProductionStatisticsDisplay class would look like.

Code Snippet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class ProductionStatisticsDisplay : IObserver, IDisplayElement
{
  private double _widgetRate;
  private double _gizmoRate;
  private double _averageWidgetRate;
  private double _averageGizmoRate;
  private ISubject _factoryProductionData;

  public ProductionStatisticsDisplay(ISubject factoryProductionData)
  {
	_factoryProductionData = factoryProductionData;
	_factoryProductionData.RegisterObserver(this);
  }

  public void Update(double widgetRate, double gizmoRate)
  {
	_widgetRate = widgetRate;
	_gizmoRate = gizmoRate;
	UpdateAverageProductionRates();
	Display();
  }

  private void UpdateAverageProductionRates()
  {
	//code to update average production rates, _averageWidgetRate and _averageGizmoRate
  }

  public void Display()
  {
	//code here to display _averageWidgetRate and _averageGizmoRate
  }
}

At this point the wiring is finished. If you're wondering where the objects get initialized such that the default constructors are called, that would be in a class similar to that shown below.

Code Snippet
1
2
3
4
5
6
7
8
9
10
11
12
13
public class ThingsFactory
{
  public ThingsFactory()
  {
	FactoryProductionData = new FactoryProductionData();
	CurrentProductionRatesDisplay = new CurrentProductionRatesDisplay(FactoryProductionData);
	ProductionStatisticsDisplay = new ProductionStatisticsDisplay(FactoryProductionData);
  }

  public FactoryProductionData FactoryProductionData { get; set; }
  public CurrentProductionRatesDisplay CurrentProductionRatesDisplay { get; set; }
  public ProductionStatisticsDisplay ProductionStatisticsDisplay { get; set; }
}

Our code has come a long way since the first implementation, but there's still more we could do. Take a look at the Update() method on the CurrentProductionRatesDisplay class. We pass two arguments to it (widgetRate and gizmoRate). Now let's say we have another metric (doodadRate) but we want to display that separately from the widgets and the gizmos via a new class called CurrentDoodadRateDisplay shown below.

Code Snippet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class CurrentDooDadRateDisplay : IObserver, IDisplayElement
{
  private double _doodadRate;
  private ISubject _factoryProductionData;

  public CurrentDooDadRateDisplay(ISubject factoryProductionData)
  {
	_factoryProductionData = factoryProductionData;
	_factoryProductionData.RegisterObserver(this);
  }

  public void Update(double widgetRate, double gizmoRate, double doodadRate)
  {
	_doodadRate = doodadRate;
	Display();
  } 

  public void Display()
  {
	//code here to display _widgetRate and _gizmoRate
  }
}

As you can see, the Update() method now takes three arguments (widgetRate, gizmoRate, and doodadRate). This likewise would require us to change the call to NotifyObservers() on the FactoryProductionData class to pass doodadRate as well. Worse yet, we'd have to update all other observers (CurrentProductionRatesDisplay and ProductionStatisticsDisplay) to accept a third argument they don't even care about. What a pain!

The solutions lies in allowing the observers to pull the information rather than the subject pushing it. Using the newspaper analogy again, it'd be the same as a subscriber saying "Hey, I only care about the Sports and International News sections, so I'll just go get that information. I don't need you to send me an entire newspaper with tons of info I don't care about."

This is easily accomplished by adding a few more lines of code to the FactoryProductionData class to allow observers to access its data. Below is the updated version.

Code Snippet
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
public interface IObserver
{
  void Update();
}
	
public interface ISubject
{
  void RegisterObserver(IObserver observer);
  void RemoveObserver(IObserver observer);
  void NotifyObservers();
  double GetWidgetRate();
  double GetGizmoRate();
  double GetDoodadRate();
}

public class FactoryProductionData : ISubject
{
  private List<IObserver> observers;
  private double widgetRate;
  private double gizmoRate;
  private double doodadRate;

  public FactoryProductionData()
  {
	observers = new List<IObserver>();
  }

  public void RegisterObserver(IObserver observer)
  {
	observers.Add(observer);
  }

  public void RemoveObserver(IObserver observer)
  {
	observers.Remove(observer);
  }

  public void NotifyObservers()
  {
	foreach (var observer in observers)
	{
	  observer.Update();
	}
  }

  public void ProductionRatesChanged()
  {
	NotifyObservers();
  }

  public double GetWidgetRate()
  {
	return widgetRate;
  }

  public double GetGizmoRate()
  {
	return gizmoRate;
  }

  public double GetDoodadRate()
  {
	return doodadRate;
  }
}

public class CurrentProductionRatesDisplay : IObserver, IDisplayElement
{
  private double _widgetRate;
  private double _gizmoRate;
  private ISubject _factoryProductionData;

  public CurrentProductionRatesDisplay(ISubject factoryProductionData)
  {
	_factoryProductionData = factoryProductionData;
	_factoryProductionData.RegisterObserver(this);
  }

  public void Update()
  {
	_widgetRate = _factoryProductionData.GetWidgetRate();
	_gizmoRate = _factoryProductionData.GetGizmoRate();
	Display();
  }

  public void Display()
  {
	//code here to display _widgetRate and _gizmoRate
  }
}

public class CurrentDooDadRateDisplay : IObserver, IDisplayElement
{
  private double _doodadRate;
  private ISubject _factoryProductionData;

  public CurrentDooDadRateDisplay(ISubject factoryProductionData)
  {
	_factoryProductionData = factoryProductionData;
	_factoryProductionData.RegisterObserver(this);
  }

  public void Update()
  {
	_doodadRate = _factoryProductionData.GetDoodadRate();
	Display();
  }

  public void Display()
  {
	//code here to display _widgetRate and _gizmoRate
  }
}

Each observer can now get only the information it needs from the FactoryProductionData. As new information is introduced (gadgetRate etc.) the ISubject interface and FactoryProductionData class will need to be updated but nothing else. Every other observer can just keep right on humming with no concern for the new piece of information.

That'll conclude the lesson the Observer Pattern. If you look back at the downsides to the original implemenation, you can see that we have addressed all of them.

  • Display elements can now be added at will as each registers as an observer. FactoryProductionData is indifferent to how many there are
  • We're now coding to interfaces (IObserver and ISubject) instead of implementations
  • Our display elements can now be added or removed at runtime via the RegisterObserver() and RemoveObserver methods
  • With the addition of pulling data instead of pushing it, we have isolated that which changes from that which does not

If anyone has thoughts or examples where you've used it before, I'd love to hear them.

portrait title

About Scott

I am a software engineer from Bozeman, MT enjoying the slightly warmer climate of Colorado. I think code can change lives. I think lives are worth changing. I write code.

You can find me on Twitter, LinkedIn, , and Github.