Amazon.com Widgets Delphi and the Observer Pattern

Delphi and the Observer Pattern

By Nick at January 27, 2013 20:46
Filed Under: Delphi, Patterns, Software Development

I’m currently reading Head First Design Patterns, and am finding it very useful and educational.  One problem, though – it’s all in Java.  So I thought that as part of the exercises, I’d translate the code to Delphi.  And also as part of my learning process, I thought it would be a good idea to post an article about each of the patterns.  I also encourage you to buy the book and read it for yourself.

The first real pattern that the book shows is the Observer Pattern.  You should use the observer pattern when you have one object that notifies other objects when events occur.    Or more succinctly, use it when you have an object that needs to notify other objects about stuff that happens. 

HFDP uses the example of a simple weather station that gathers data about the weather.  Each time the weather station takes readings, it needs to update the views of that weather. The weather station reports on Temperature, Humidity, and Pressure.  There are three views that the application provides – current conditions, statistics about the weather, a simple forecast.

The idea here is that the weather station is the subject – it is the object being observed and doing the notifying.  The different displays for the information are the observers – they watch what happens on the weather station and update themselves based on the notifications that they receive from the weather station.  Another way to look at it is that the weather station is a publisher of information, and the displays are subscribers.

The formal definition given for the Observer Pattern goes like this: 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. 

But when it comes time to implement this, the temptation is to simply embed the displays inside of a method of the weather station.  You might create classes for each view, instantiate them in the weather stations constructor, and then simply update the views in a method called MeasurementsChanged.

But of course if you do this, you are breaking some of the base design rules.  First, you’d be coding against an implementation instead of against an interface.  Second, you’ve made it really hard to add a new data display should that become necessary.  Displays are hard-coded into the weather station and can’t be added or removed at runtime.  If we do want to add more displays, we’d need to modify the weather station itself.  Or, put more succinctly, the weather station and its displays are tightly coupled to each other.  And if you know one thing about me, I abhor tight coupling.  And you should too.

In any event, there is a better way – the Observer Pattern.  As noted above, observer pattern consists of a Subject that is monitored by Observers.   We’ll implement a very simple version of the observer pattern. The first thing we will do of course, is declare two interfaces:

type
  IObserver = interface
  ['{69B40B25-B2C8-4F11-B442-39B7DC26FE80}']
    procedure Update(aTemperature: integer; aHumidity: integer; aPressure: Double);
  end;

  ISubject = interface
  ['{A9240295-B0C2-441D-BD43-932AF735832A}']
    procedure RegisterObserver(aObserver: IObserver);
    procedure RemoveObserver(aObserver: IObserver);
    procedure NotifyObservers;
  end;

The first interface is IObserver, which the observing classes will implement.  In it they’ll be updated with all the weather information that the weather station has for us.  The second is ISubject, which will be implemented by the weather station.  It takes three methods, two for handling the connecting and disconnecting of IObservers, and the third for doing the actual notification to the observers. 

The first implementation we’ll look at is the Weather Station.  Here is its implementation declaration.

type
  TWeatherData = class(TInterfacedObject, ISubject)
  private
    FTemperature: integer;
    FHumidity: integer;
    FPressure: double;
    FObserverList: TList<IObserver>;
    function GetTemperature: integer;
    function GetHumidity: integer;
    function GetPressure: double;
  public
    constructor Create;
    destructor Destroy; override;
    procedure SetWeatherInformation(aTemperature: integer; aHumidity: integer; aPressure: double);
    procedure RegisterObserver(aObserver: IObserver);
    procedure RemoveObserver(aObserver: IObserver);
    procedure NotifyObservers;
    procedure MeasurementsChanged;
    property Temperature: integer read GetTemperature;
    property Humidity: integer read GetHumidity;
    property Pressure: double read GetPressure;
  end;

The plumbing for managing the weather implementation is all what you’d expect.  The interesting part, of course, is the implementation of ISubject.  Internally, it uses a TList<IObserver> to manage all the observers that get registered with it.  The RegisterObserver and RemoveObserver methods simply insert and remove, respectively, instances of classes that implement the IObserver interface.

The real action occurs in the NotifyObservers method.  We’ll get to that in a second.  First, though, let’s take a look at the observers.  Since all the displays are very similar, this is a good time to use good old-fashioned inheritance to declare a base class that implements the needed functionality, and then have descendent classes that do the work of providing the specified displays.  Here, then, is the interface for TWeatherDataDisplay:

TWeatherDataDisplay = class(TInterfacedObject, IObserver, IDisplay)
  private
    FSubject: TWeatherData;
    FTemperature: integer;
    FHumidity: integer;
    FPressure: Double;
  public
    constructor Create(aWeatherData: TWeatherData);
    destructor Destroy; override;
    procedure Update(aTemperature: integer; aHumidity: integer; aPressure: Double); virtual;
    procedure Display; virtual; abstract;
  end;

TWeatherDataDisplay has fields to keep track of the current weather information.  It’s descendants can do with it as they please.  It also implements the IDisplay interface so that it can report out what it has to say.  The Update method will allow the Subject – in this case the weather station – to update the displays.  Update is a virtual method, by the way, so that descendants can do different things with the incoming information. 

Okay, so let’s look under the hood.  The weather station can accept and remove IObserver implementers at runtime.   implements the NotifyObservers method as part of the ISubject interface.  It gets called whenever the weather information changes.  It is implemented as follows:

procedure TWeatherData.NotifyObservers;
var
  Observer: IObserver;
begin
  for Observer in FObserverList do
  begin
    Observer.Update(Temperature, Humidity, Pressure);
  end;
end;

This is pretty simple – it merely enumerates over each item in the observer list and calls the Update method, passing along the new weather data.  The base class stores the information, and its descendants process it.

The real “work” gets done when the weather station updates the temperature data and calls NotifyObservers:

procedure TWeatherData.SetWeatherInformation(aTemperature, aHumidity: integer; aPressure: double);
begin
  FTemperature := aTemperature;
  FHumidity := aHumidity;
  FPressure := aPressure;
  MeasurementsChanged;
end;

The entire implementation of our little weather station can be found as part of my demo code on BitBucket.org.

So all of this comes together in a method to create a weather station and add observers:

procedure DoWeatherStation;
var
  WeatherStation: TWeatherStation;
  CurrentDisplay: IDisplay;
  ForecastDisplay: IDisplay;
  StatsDisplay: IDisplay;
begin
  WeatherStation := TWeatherStation.Create;
  try
    CurrentDisplay := TCurrentConditionsDisplay.Create(WeatherData);
    ForecastDisplay := TForecastDisplay.Create(WeatherData);
    StatsDisplay := TStatisticsDisplay.Create(WeatherData);;
    WeatherStation.SetWeatherInformation(70, 55, 28.90);
    WeatherStation.SetWeatherInformation(68, 59, 28.96);
    WeatherStation.SetWeatherInformation(35, 66, 27.40);
    WeatherStation.SetWeatherInformation(55, 55, 27.40);

  finally
    WeatherStation.Free;
  end;
end;

Here are some interesting things to note:

  • This code doesn’t write anything to the console.  All of that is done by the display objects that get registered as observers.  Each observer is registered, and the code pretty much forgets about them.  To the weather station, they are merely IObserver interfaces, and the only thing you can do to an IObserver is call it’s Update method.  From the Weather Station’s perspective, there’s nothing else to it.
  • Four calls to SetWeatherInformation result in for reports from all of the updates to the temperature information.
  • Once you have a reference to a TWeatherStation, you can add or remove displays at runtime.
  • TWeatherStation doesn’t know anything about Weather displays – it only knows about IObservers.  This means that you could have observers that do other things besides being Weather Displays.  You could simply store the weather data, or anything else at all.  For instance, you could create a TWriteWeatherInfoToDatabase class that implements the IObserver interface.  The Weather Station itself neither knows nor cares.  IObservers are under no obligation to do anything specific with the data passed to them. 
  • We can change the observers anytime we want without altering the Subject.  We can add new observers, too.  Basically, observers and subjects are very loosely coupled, and either can be changed, altered, updated, and added to without having to worry about changing the other. 

So that should be a quick rundown on how the observer pattern works.  The obvious weakness here is that our IObserver interface is very specific to weather data.  You can create your own interface for your specific implementation.  The pattern remains the same no matter how the IObserver interface is designed.  This is obviously a good place for generics to enter the picture, and in fact, the Delphi Spring framework implements a generic IObservable<T> interface and implementing class.

So in summation, the Observer pattern ensures that publishing classes (subjects) can communicate updates to their subscribing (observer) classes with very loose and flexible coupling.  Observers can be updated and removed at runtime.  Adding observers requires no change to subjects.  Subjects don’t know much at all about what the observers are up to.  It’s all very easy and elegant and loosely coupled – just like you want it.

Next up – the Decorator Pattern.

Comments (23) -

1/28/2013 12:00:03 AM #

I find in my implementations that IObserver needs one more method... (My apologies for not knowing the correct mark-up for code fragments in this comment feed.)

[code]
IObserver = interface
  ['{69B40B25-B2C8-4F11-B442-39B7DC26FE80}']
    procedure Update(aTemperature: integer; aHumidity: integer; aPressure: Double);
    procedure DereferenceSubject( const Subject: ISubject);
  end;
[/code]

If the observers need to keep a reference to the subject (which is indeed the case in most of my implementations), the usual implementations for this create a structure with circular references. This is not a problem until it comes time to shut-down. The ideas is that when the subject needs to shutdown, it calls DereferenceSubject() on all of it's observers before unsubscribing them. An observer, upon recieving the DereferenceSubject() releases any references it has to the subject, breaking circular reference and allowing the normal reference-counting life-cycle management to kick in.

I'm curious. Does any-one else commonly include a DereferenceSubject() method in their IObserver interface?

Sean B. Durkin Australia |

1/28/2013 3:49:38 AM #

@Sean : no I don't

[code]
  IItemObserver = interface
    ['{8B1211C7-5799-486F-A66C-EF999D087229}']
    procedure UpdateObserver(const aObservable: IObservable);
  end;
[/code]

I just call UpdateObserver(nil) to dereference the subject.
(in my code IObservable is same as ISubject I think)

D. Demars France |

1/28/2013 1:20:35 AM #

1. Sean is perfectly right: when working with interfaces, circular references comes in mind.

As usual with simple examples, like the once about "Temperature notification", KISS implementation works well, but when it comes to real world code, it is more difficult than expected.
Delphi's implementation of interfaces lacks of either a garbage collector (as C# or Java do (ab)use), or at least a native weak reference support (as with Apple's ARC model). See blog.synopse.info/.../Avoiding-Garbage-Collector%3A-Delphi-and-Apple-on-the-same-side

There is a new memory model on the road within Delphi (sounds pretty much ARC-like, including direct [weak] references), but it is not yet ready, I suppose. You can see some traces of it in the XE3 RTL. See blog.synopse.info/.../Delphi-XE3-is-preparing-reference-counting-for-class-instances

I see two possible solutions, while waiting for a memory model enhancement (I hope it is an enhancement, not a substitution):

A) Implements (zeroing) weak references.
For our framework, which relies a lot in interfaces for publishing client/server services, or creating stubs/mocks, we also included a weak pointer reference function and an optimized "zeroing" weak pointer feature - see blog.synopse.info/.../Circular-reference-and-zeroing-weak-pointers

B) Use COW (copy on write) value objects instead of reference to classes.
In this case, a good old "record" (with its methods, if needed) does the trick, and is efficient.
Or you can use your own copy of the supplied "Subject" interface, if it features a "clone" explicit method.

2) This "Observer pattern" is the way to implement Event-Driven interfaces (which we'll implement natively soon in mORMot, too).

See martinfowler.com/eaaDev/EventCollaboration.html
But even if it sounds pretty simple from the book point of view, it could also lead to some new unexpected results.
Using such pattern can lead to some new problems very difficult to track: explicit method calls are easy to follow, but the publish/subscribe pattern creates some uncoupled code, and when the project starts to grow, even more if you allow third-parties to subscribes to your system events, it could become a nightmare to debugg!
So as stated by Martin Fowler in his article, ensure that you are using the Observer pattern only if you use it.

A.Bouchez France |

1/29/2013 3:23:11 AM #

There is a third option, which is technically more complex but preferable IME, which is to use an ARC - GC hybrid, the ARC takes care of immediate release in all simple cases, and the GC takes care of the cycles. Since the GC only has to take care of cycles, it can run less frequently and it doesn't have to stall execution during collection phases (since it'll only ever collect interfaces that are stuck in cycles and not reachable anymore).

And yes, the debugging issue can be non-trivial, and are furthered by the debugger not being very smart when inspecting an interface (lots of manual stuff to type if you want to inspect the fields of an object behind an interface f.i.). With improved debugger support, this could become more convenient though.

Eric France |

2/8/2013 3:06:27 PM #

You are right: this hybrid ARC + GC model is also an option.

It is the one implemented in DelphiWebScript, if I remember well.
;)

Arnaud Bouchez France |

1/28/2013 9:43:45 AM #

Thanks Nick!  I've had a hard time concentrating on and getting my head around design patterns.  I've looked at the HF books and muttered "Ugh.  Java.".  Your clear and concise description of this pattern written in Delphi allows me to get both the "why" and the "how" at the same time.  I'm really looking forward to your posts on this.

Thanks!!!

Bob Kellum United States |

1/28/2013 12:54:23 PM #

Thanks for doing this. I, too, started to read through HFDP and got totally turned off by the Java examples so this is great.

Charles Hodgkins United States |

1/28/2013 1:48:20 PM #

I began myself writing a series of Delphi examples aiming to explain the classic design patterns as defined in "Design Patterns (Elements of reusable Object-Oriented Software)" by the "Gang of Four" (GOF).

I never finished the series for lack of time. I interleaved other non-classic patterns like Dependency Injection. This is what I wrote so far (Singleton, Multiton, Template Method, Decorator, Factory Method, Dependency Injection): <a href="www.yanniel.info/.../Design%20Patterns">Design Patterns in Delphi</a>.

"Head First Design Patterns" as mentioned by Nick is a really good book on the topic. Most people find it easier to read in compassion with "Design Patterns (Elements of reusable Object-Oriented Software)". Nonetheless, my personal choice is the GOF book.

Guys, no matter how much you love Delphi (which I certainly do) is not an excuse for not reading the C++ or Java examples in the above mentioned books. The knowledge of C++ or Java needed is pretty basic.  

Thanks a lot Nick for the article.

  Yanniel.

Yanniel Canada |

1/28/2013 1:51:45 PM #

I screwed up the link above. Here it is again: www.yanniel.info/search/label/Design%20Patterns

Yanniel Canada |

1/28/2013 3:54:24 PM #

Yanniel --

Yes, your stuff is great.  I'll be sure to link to your articles.  Excellent stuff.  

nick United States |

1/28/2013 6:39:20 PM #

Glad to contribute Wink

Yanniel Canada |

1/28/2013 6:22:00 PM #

I'm looking for an example of doing the Observer pattern across thread boundaries. In other words, I want to find a cross-platform way to handle notifications in Delphi, the way "signals and slots" work in Qt. I can easily conceive of how one might do this in Windows, using Windows messages to tell the main thread to look for something in a threadsafe queue, but when you get to code that also needs to work in OSX, iOS and eventually Android, another scheme is needed. Any ideas?

John Jacobson United States |

1/29/2013 3:17:22 AM #

No free meal on that problem if you want good performance: you need to use the thread-safe queue mechanism that works best on each platform, and which mechanism works best depend on what you're doing exactly. For instance on Windows the messages can work well for UI apps with infrequent messages, but in other cases you need to use IOCP.

If performance isn't an issue, then any thread-safe queue will do, even a simple non-thread-safe queue protected by a mutex or critical section could be enough.

Eric France |

1/28/2013 8:07:36 PM #

I like your article on the Observer Pattern; easy to understand.  I only use 4-5 Design Patterns, but they have really taken my coding to the next level.

It's interesting to note that Design Pattern's are size agnostic.  The weather station and it's Observer's are one size.  But an ActionListManager conducts an Observer pattern inside a single process, a much smaller size.

The ActionListerManager is very powerful.  Too bad it breaks form inheritance. (which I use alot.)

Here's a Hint: the Memento Pattern is cool for collecting and storing large collections of Parameters, for, say, complex reports.

Keep up the good work Nick.

Keith United States |

1/29/2013 3:20:37 AM #

This time I have to say I am kind of disappointed with your article. ;)

As someone using Spring you should have stopped implementing the observer pattern "old school" using these subscriber and observer interfaces and use events instead. Events are actually a reusable implementation of the observer pattern. You notice that in explitly implementing code you have the exact code all over the place again adding, removing and looping over the observers. Sure you can create or use a base class (like the one from Spring you mentioned). But the more elegant way is to use events.

Stefan Glienke Germany |

1/29/2013 9:36:54 AM #

Stefan ---

Sorry to disappoint you.  Wink

My intent here is to mirror what the Head First book does to make it easier and more approachable for Delphi developers.  I certainly can, in the future, write about more modern ways to do the Observer pattern (and others), but right now, it's merely to aid in opening the HFDP book to Delphi developers.

I do appreciate the feedback, however.  

nick United States |

1/29/2013 3:41:13 AM #

Nick,

you should consider to store the observers in the subject without increasing the reference counter. You can do this with the help of an interface storer.
Please remember that an observer is valid as long as RemoveObserver is called.

--
Thanks,

Roman

Roman Germany |

2/2/2013 2:59:07 PM #

Nick, will you do me a favour, please?

Will you stop(and not just you, please people stop this!!) putting the interface methods in the public section?

They don't pertain there, they shouldn't be there. Personally, I always put them in protected or, for specific instances, private.
Why? Because an interface is an "aspect" of a class and its methods should be only accessible when using the interface.
If you access an interface method when you're using the object, then you are risking bad things happening in my opinion.
Regards,

A

Andrea Raimondi United Kingdom |

2/3/2013 3:00:21 PM #

Huh? What kind of bad things can happen? Interface describes class functionality and belongs to public area.

Dalija Prasnikar Croatia |

2/2/2013 3:08:19 PM #

Oh and just because I am picky Smile

The IDisplay really should be a property, because otherwise you give to one object two responsibilities: one to get notified and another to display the values.
Instead, by decoupling the IDisplay, you only give it one: to get notified and delegate the display to someone else.

Regards,

A

Andrea Raimondi United Kingdom |

2/3/2013 3:50:58 PM #

I disagree Smile

Interfaces are aspects of objects and as such they should only be used.
Exposing the interface as public means you can use the interface methods on an object, which is wrong in my opinion.
Besides, it blurs the distinction between interfaces and objects, then if someone accesses the internal object(GetObject:TObject anyone??), bad things will potentially happen whereas having them hidden away at least tells you "something is wrong".
Regards
A

Andrea Raimondi United Kingdom |

2/4/2013 3:00:33 AM #

There is absolutely no difference if you call the method on the interface or object and actually no "bad things" can happen. Also not all interfaces are aspects. Some are and in these cases you might use interface delegation anyway.

Stefan Glienke Germany |

2/4/2013 12:54:33 PM #

Exactly. There is no difference between calling method on interface or object.

Dalija Prasnikar Croatia |

Pingbacks and trackbacks (1)+

Comments are closed

My Book

A Pithy Quote for You

"You cannot increase the water in a swimming pool by taking water from the deep end and pouring it into the shallow end."    –  Me

Amazon Gift Cards

General Disclaimer

The views I express here are entirely my own and not necessarily those of any other rational person or organization.  However, I strongly recommend that you agree with pretty much everything I say because, well, I'm right.  Most of the time. Except when I'm not, in which case, you shouldn't agree with me.

Month List