Joanna Carter

June 30, 2004

The Observer Pattern

Filed under: Design Patterns — Joanna Carter @ 3:29 pm

Introduction

When we use Delphi to design forms and data modules, every time we place a component on the designer, several things change: the form now shows an appropriate representation of the component, the object inspector changes to show the properties of the component and, if we press Alt-F12, we see the .DFM file now contains information about the component. Whether this behaviour was modelled correctly on the Observer pattern or not, the result is that several ‘interested parties’ got to know about a change in the content of the project that we are working on.

If you read the GoF Design Patterns book, you will find much discussion on the semantics and structure of the Observer pattern. Do we want to have one subject and many observers; do we want to have many subjects and one observer; or do we want many observers to keep track of many subjects? The answer to these questions will depend to a great extent on the application that you find yourself developing. Delphi, for example may be seen as using all of these variants in some part of the IDE.

In the same book, you will see that in order to implement the Observer pattern to implement a Digital Clock observer that relates to a Clock Timer subject, use is made of multiple inheritance. But Delphi does not support multiple inheritance… "No, not that old chestnut again!", I hear you cry, "Surely what we need in Delphi v10 is multiple inheritance?". Well, yes and no.

There are two primary mechanisms for circumventing a lack of multiple inheritance: Composition and Interfaces.

Abstract Concepts

Let us start by looking at the abstract concepts of Observers and Subjects as discussed in Gamma’s book:


IObserver
procedure Update(Subject: IInterface);

ISubject
procedure Attach(Observer: IObserver);
procedure Detach(Observer: IObserver);
procedure Notify;


As you can see the basic idea of an Observer is that it can be told when the Subject has changed; this is achieved when the Subject calls the Observer.Update method and passes itself as the Subject parameter. The ISubject consists of methods for attaching and detaching IObservers as well as a Notify method, which iterates through any Observers that are attached.

Composition


If you are not comfortable with using interfaces, which is the simplest way of implementing the Observer pattern, then you need to use Composition to supply the necessary additional functionality to existing classes. Composition involves the placing of an instance of a class that implements a desired behaviour inside a derivative of the class that needs to be extended.


TObserver = class
public
procedure Update(const Subject: TObject); virtual; abstract;
end;

TSubject = class
private
fController: TObject;
fObservers: TObjectList;
public
constructor Create(const Controller: TObject);
procedure Attach(const Observer: TObserver);
procedure Detach(const Observer: TObserver);
procedure Notify;
end;


We start off by writing an abstract class for the Observer that provides a method called Update that can be overridden, depending on the class that is to be an Observer. The Subject class can take care of managing the list of Observers and the broadcasting of updates to them.


constructor TSubject.Create(const Controller: TObject);
begin
inherited Create;
fController := Controller;
end;

procedure TSubject.Attach(const Observer: TObserver);
begin
if fObservers = nil then
fObservers := TObjectList.Create;
if fObservers.IndexOf(Observer) < 0 then
fObservers.Add(Observer);
end;

procedure TSubject.Detach(const Observer: TObserver);
begin
if fObservers <> nil then
begin
fObservers.Remove(Observer);
if fObservers.Count = 0 then
begin
fObservers.Free;
fObservers := nil;
end;
end;
end;

procedure TSubject.Notify;
var
i: Integer;
begin
if fObservers <> nil then
for i := 0 to Pred(fObservers.Count) do
TObserver(fObservers[i]).Update(fController);
end;


The constructor for the TSubject class takes a TObject as a ‘Controller’ parameter and this object is retained for use as the ‘real’ Subject to be sent to each of the Observers; otherwise all the Observers will see is a TSubject and not the actual subject class.

Watching the Clock


The GoF book uses the example of a digital clock to demonstrate the principles of the Observer pattern and we will use that same example here.

Let’s start by designing a simple class to represent the Clock mechanism:


TClockTimer = class
private
fTimer: TTimer;
fInternalTime: TDateTime;
fSubject: TSubject;
procedure Tick(Sender: TObject);
public
constructor Create;
destructor Destroy; override;
function GetTime: TDateTime;
property Subject: TSubject
read fSubject;
end;


This particular clock uses a TTimer to keep its own time and for the purpose of this example will update itself every second.

The signature of the Tick method is that of a TNotifyEvent in order to simplify the handling of the timer interval. In the Tick Method, I set an internal variable to the current time to avoid any difference in time portrayed between calls to GetTime by the attached Observers.


constructor TClockTimer.Create;
begin
inherited Create;
fTimer := TTimer.Create(nil);
fTimer.Interval := 1000;
fTimer.OnTimer := Tick;
fTimer.Enabled := True;
fSubject := TSubject.Create(self);
end;

destructor TClockTimer.Destroy;
begin
fSubject.Free;
fTimer.Enabled := False;
fTimer.Free;
inherited Destroy;
end;

function TClockTimer.GetTime: TDateTime;
begin
Result := fInternalTime;
end;

procedure TClockTimer.Tick(Sender: TObject);
begin
fInternalTime := Now;
fSubject.Notify;
end;


Notice the inclusion of a private TSubject field that will allow us to notify the list of Observers. The constructor not only creates the instance of TSubject, it also passes itself to the Subject constructor, so that the Subject can have a TClockTimer to pass to the Observers during the Notify method.

Every time the TTimer.OnTimer event fires, the internal time field is updated to the current time and then the Subject’s Notify event is called.

Putting on a Face


Now we have a clock mechanism, we also need a face for our clock; a way of displaying the time provided by the mechanism.


TDigitalClock = class;

TClockObserver = class(TObserver)
private
fDisplay: TDigitalClock;
public
constructor Create(const Display: TDigitalClock);
procedure Update(const Subject: TObject); override;
end;

TDigitalClock = class(TPanel)
private
fObserver: TClockObserver;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
property Observer: TClockObserver
read fObserver;
procedure ObserverUpdate(const Subject: TClockTimer);
end;


As we have said before, Delphi does not support multiple inheritance and so, to be able to derive our Digital Clock face from TPanel we also need to use composition to mix a TObserver class with the TDigitalClock class. Note also that we have to ensure that the Update method of TPanel is not suitable for responding to calls to TObserver.Update, therefore we have called our method ObserverUpdate to avoid confusion.

Just as we had to pass in the Clock Timer to the Subject, we also have to pass the Digital Clock to the Observer. The Update method of TClockObserver will call ObserverUpdate in TDigitalClock to allow the Text property of the TPanel to be updated.


constructor TClockObserver.Create(const Display: TDigitalClock);
begin
inherited Create;
fDisplay := Display;
end;

procedure TClockObserver.Update(const Subject: TObject);
begin
if (Subject is TClockTimer) then
fDisplay.ObserverUpdate(TClockTimer(Subject));
end;


The Clock Observer class derives from TObserver and overrides the Update method to check if the Subject being passed is indeed a TClockTimer and then passes that Clock Timer to the ObserverUpdate method of the Digital Clock.


constructor TDigitalClock.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
fObserver := TClockObserver.Create(self);
end;

destructor TDigitalClock.Destroy;
begin
fObserver.Free;
inherited Destroy;
end;

procedure TDigitalClock.ObserverUpdate(const Subject: TClockTimer);
begin
Text := FormatDateTime(’tt’, Subject.GetTime);
end;


All that is left for the display class to do is to respond to the update by setting the Text property to the value provided by the Clock Timer subject.

Observer Interfaces


Instead of using Composition to circumvent the lack of multiple inheritance, we can also use Interfaces in a way that allows us to support the concept of deriving a class that ‘inherits’ the behaviour of more than one type.

When describing multiple inheritance, the example of an amphibious vehicle is often used. But the concept of an amphibious vehicle does not truly represent an object that is truly a car and truly a boat; surely it is, more accurately, a vehicle that can behave like a car or like a boat. What interfaces allow us to do is to design classes that support multiple behaviours. So let us go on to look at how we can simplify the Observer pattern using interfaces.


IObserver = interface
['{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}']
procedure Update(Subject: IInterface);
end;

ISubject = interface
['{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}']
procedure Attach(Observer: IObserver);
procedure Detach(Observer: IObserver);
procedure Notify;
end;


In the above example using Composition, we had to write an abstract class called TObserver that had just the one method, Update, but if you look at these interface declarations, you actually have the equivalent of an abstract class. Essentially an interface is almost the same as an abstract class with a few more features like reference counting and the ability to be mixed with other interfaces in a class.

As with the non-interface method of implementing the Observer pattern, we can implement the ISubject interface once and for all and aggregate an instance of TSubject into our Subject class to avoid rewriting the same code over and over again.


TSubject = class(TInterfacedObject, ISubject)
private
fController: Pointer;
fObservers: IInterfaceList;
procedure Attach(Observer: IObserver);
procedure Detach(Observer: IObserver);
procedure Notify;
public
constructor Create(const Controller: IInterface);
end;


Gamma uses a template List container class to maintain the list of Observers, but as we are not using C++ we will use a IInterfaceList as this is the correct way to store lists of references to interfaces. So let’s go on to look at the implementation for this base TSubject class:


constructor TSubject.Create(const Controller: IInterface);
begin
inherited Create;
fController := Pointer(Controller);
end;

procedure TSubject.Attach(AObserver: IObserver);
begin
if fObservers = nil then
fObservers := TInterfaceList.Create;
fObservers.Add(AObserver);
Notify;
end;

procedure TSubject.Detach(AObserver: IObserver);
begin
if fObservers <> nil then
begin
fObservers.Remove(AObserver);
if fObservers.Count = 0 then
fObservers := nil;
end;
end;

procedure TSubject.Notify;
var
i: Integer;
begin
if fObservers <> nil then
for i := 0 to Pred(fObservers.Count) do
(fObservers[i]. as IObserver).Update(IInterface (fController));
end;


The constructor takes an IInterface reference to the aggregating object (in our example the Clock Timer) and stores it in a Pointer field; this ‘weak reference’ technique avoids reference-counting problems that could cause a memory leak due to the mutual references between the TSubject and its aggregating class.

The Attach and Detach methods are fairly straightforward, but I will go into a little more detail with the Notify method. This method traverses the list of Observers that are attached to the Subject and calls the Update method for each observer that it finds. The fController field that is the real subject (Clock Timer) has to be cast back to an IInterface in order to be passed to the Update method of the Observer interface.

A Universal Ticker


Here is the interface definition for the ‘mechanism’ of our clock:


IClockTimer = interface
['{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}']
function GetTime: TDateTime;
end;


The declaration of the TClockTimer implementing class is slightly different from the non-interface version. Instead of deriving from TObject, it derives from TInterfacedObject in order to give us a ready-made implementation of IInterface and then also implements the Clock Timer and Subject interfaces.


TClockTimer = class(TInterfacedObject, IClockTimer, ISubject)
private
fTimer: TTimer;
fInternalTime: TDateTime;
fSubject: ISubject;
function GetTime: TDateTime;
procedure Tick(Sender: TObject);
property Subject: ISubject
read fSubject
implements ISubject;
public
constructor Create;
end;


The main differences are: all methods (apart from the constructor) and properties are now private because they will only be accessed through the supported Interfaces. The Subject property is declared with the implements directive so that any attempt to reference the ISubject interface will be redirected to the embedded TSubject instance.


destructor TClockTimer.Destroy;
begin
fTimer.Enabled := False;
fTimer.Free;
inherited Destroy;
end;


The only difference in the code required for the interface version of this class is the omission of the call to fSubject. Free; this is not necessary or possible, as it will automatically fall out of scope when the Clock Timer is destroyed and Free is not a method of IInterface.

Widgets and Other Furry Animals


In Gamma’s book, the Digital Clock class is derived from a Widget class and from the abstract Observer class previously discussed. As we are not able to use multiple inheritance, we are going to have to find another way of implementing a Widget that is also an Observer. For a very simple demonstration component that you can put on a form, I decided that my ‘Widget’ would be a TPanel. Here is the class declaration:


TDigitalClock = class(TPanel, IObserver)
private
procedure IObserver.Update = ObserverUpdate;
procedure ObserverUpdate(const Subject: IInterface);
end;

procedure TDigitalClock.ObserverUpdate(const Subject: IInterface);
var
Obj: IClockTimer;
begin
Subject.QueryInterface(IClockTimer, Obj);
if Obj <> nil then
Caption := FormatDateTime(’tt’, Obj.GetTime);
end;


Because TPanel already has an Update method that is unsuitable for our purposes, we have to redirect the IObserver.Update method to another method, which I have called ObserverUpdate.

In ObserverUpdate you will see that a check is made to ensure that the Subject being passed in is really a Clock Timer and then, if it is a valid subject, the visual representation on the ‘Widget’ is updated using the GetTime method of the Subject.

After installing this component into the VCL, the only other code needed to get a demonstration going is to declare a private variable of type IClockTimer on a test form then add a button and the following event handlers:


procedure TForm1.FormCreate(Sender: TObject);
begin
fClockTimer := TClockTimer.Create;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
(DigitalClock1 as ISubject).Attach(fClockTimer as IObserver);
end;


Any number of Digital Clocks can be placed on the form and attached to the Clock Timer and they will all be notified and kept up to date every second.

14 Comments »

  1. Another great article. Keep them coming!

    Comment by Dominique Louis — July 13, 2004 @ 8:13 pm

  2. Great article. Detailing into the alternatives of composition and interfaces gives the reader the ability to choose what suits her/him best.

    Potential future revisions could take the chance to include the idea of Message parameters to the Notify/Update-methods.

    Comment by Malte Persike — July 14, 2004 @ 4:02 am

  3. Great article - even a beginner in OOP and patterns can understand!

    I have been waiting for your book to learn more about OOP, design patterns and MVP. Don’t hesitate to continue your work on this page. I can hardly wait.

    As far as I can see, there is a small error:

    (DigitalClock1 as ISubject).Attach(fClockTimer as IObserver);

    should be:

    (fClockTimer as ISubject).Attach(DigitalClock1 as IObserver);

    Your text is correct - but the code seems wrong (compiling gives an error).

    Regards,

    Lars

    Comment by Lars Christian Svane — August 14, 2004 @ 1:55 am

  4. Sorry to disturb you again. But something I don’t understand is happening:

    I changed the code as in my last comment. Then my test application compiled and run fine - with ONE Digital Clock on the form.

    Then I added three more. And then I get an access violation when I close the application. With up to three Digital Clocks it works fine. On four - BUM!

    It happens at a place after the Interfacelist starts to be cleared. After the "finally" in Classes file.

    Can you explaine this?

    Regards,

    Lars

    Comment by Lars Christian Svane — August 14, 2004 @ 2:14 am

  5. Good article!

    But, look, if you can provide some more sofisticated examples it will be great.

    Patterns is great stuff, but Delphi itself imply a lot of limitations. Just assume that your Observer must work in threading environment and you will see what i mean.

    Some stuff in VCL might turn our life in nightmare :-(
    I know it’s not about patterns, but as far as we are talking about Delphi implementation it would be nice to see.

    Comment by Mike — August 25, 2004 @ 2:55 pm

  6. thx 4 ur article, as a php developer i really needed this :o

    thx again, like 2c more btw ;)

    Comment by thomas — September 13, 2004 @ 5:50 pm

  7. Great article! But I think there are some small problems in it.

    1 just as Lars Christian Svane said, :)
    (DigitalClock1 as ISubject).Attach(fClockTimer as IObserver);

    should be:

    (fClockTimer as ISubject).Attach(DigitalClock1 as IObserver);

    2

    fController: Pointer;

    should be:

    fController: IInterface;

    constructor TSubject.Create(const Controller: IInterface);

    begin

    inherited Create;

    fController := Pointer(Controller);

    should be:

    fController := Controller;

    end;

    procedure TSubject.Notify;

    var

    i: Integer;

    begin

    if fObservers <> nil then

    for i := 0 to Pred(fObservers.Count) do

    (fObservers[i]. as IObserver).Update(IInterface (fController));

    should be:

    (fObservers[i] as IObserver).Update(fController);

    end;

    Why?

    If fController is defined as a Pointer type, I think it is a pointer type cast and not a interface reference in code "fController := Pointer(Controller)". you have to add "Controller._AddRef;" to avoid a access violation.

    Comment by wango — October 19, 2004 @ 8:27 am

  8. > Great article! But I think there are some small

    > problems in it.

    > 1 just as Lars Christian Svane said, :)

    > (DigitalClock1 as ISubject).Attach(fClockTimer as

    > IObserver);

    > should be:

    > (fClockTimer as ISubject).Attach(DigitalClock1 as

    > IObserver);

    Yes, I should change this :-)

    > 2

    > fController: Pointer;

    > should be:

    > fController: IInterface;

    <snip>

    > Why?

    > If fController is defined as a Pointer type, I

    > think it is a pointer type cast and not a

    > interface reference in code

    > "fController := Pointer(Controller)". you have to

    > add "Controller._AddRef;" to avoid a access

    > violation.

    The use of the Pointer is known as a ‘weak reference’ and is used to break the circular refcount problem where an outer class holds a reference to an inner class and an inner class holds a reference to the outer class. This then means that neither of the refcounts get to drop to zero thus causing a memory leak. Assigning to a Pointer means that the refcount of the Controller is not incremented from the one that is holding the outer (controller) object; therefore, when that ref falls out of scope it then drops to zero releasing the outer object which, in turn releases the inner object.

    Try it :-)

    Joanna

    Comment by Joanna Carter — October 20, 2004 @ 12:18 am

  9. Great article!

    I have some remark, though:

    TClockTimer = class(TInterfacedObject, IClockTimer, ISubject)

    private

    fTimer: TTimer;

    fInternalTime: TDateTime;

    fSubject: –>ISubject<–;

    function GetTime: TDateTime;

    procedure Tick(Sender: TObject);

    property Subject: –>ISubject<–

    read fSubject

    implements ISubject;

    public

    constructor Create;

    end;

    Shouldn’t it be TSubject?



    Best regards, Ilia Frenkel.

    Comment by Ilia Frenkel — June 9, 2005 @ 1:34 pm

  10. No, using interface references for delegation is just as valid as objects as long as you are aware of the refcounting and QueryInterface implications.

    Comment by Joanna Carter — June 9, 2005 @ 1:45 pm

  11. Nice article and thanks for putting it together.

    Do you have a working example available for download? It is much easier to start with something that works and I have been completely unsuccessful in splicing

    together the various snippets.

    Comment by Mike S — March 28, 2006 @ 12:19 am

  12. Extra Reading…

    [...]we like to honor other sites on the web, even if they aren’t related to us, by linking to them. Below are some sites worth checking out[...]…

    Trackback by Buy Guaranteed Facebook Fans — November 26, 2011 @ 11:26 am

  13. [...] is to exercise a 'observer pattern'; a simple instance on that settlement pattern in Delphi has been described by Joanna Carter in her [...]

    Pingback by How is a lifeless rect perspective with clarity finished on iphone? - Adeyemo — September 10, 2014 @ 4:42 am

  14. [...] exercise a Observer Pattern in Delphi controlling interfaces, we could use this or this as a [...]

    Pingback by What is a comparison proceed of server formula notifying churned clients of information changes within a unparalleled Delphi Application? | Zetes — November 19, 2014 @ 5:10 pm

RSS feed for comments on this post. TrackBack URL

Leave a comment

You must be logged in to post a comment.

Powered by WordPress

Bad Behavior has blocked 24 access attempts in the last 7 days.

Close