Search code examples
delphiexceptionobserver-pattern

Delphi Interface inheritance and Observer Pattern


I'd like to create a generic Subject Interface and so reuse it with "specifics" Observer classes. So I tried this code for the Subject:

unit uISubject;

interface

type

    ISubject = interface(IInterface)
        procedure RegisterObserver(Observer: IInterface);
        procedure RemoveObserver(Observer: IInterface);
        procedure NotifyObservers;
    end;

implementation

end.

And I have the following classes for Observers:

An Observer for serial communication

unit uISerialObserver;

interface

type

    ISerialObserver = interface(IInterface)
    ['{EF833BD7-31C1-49B3-8041-F1574AC043F0}']
        procedure DataAvailable(ReceivedData: AnsiString);
    end;

implementation

end.

An Observer that update Progress bar

unit uIProgressObserver;

interface

type

    IProgressObserver = interface(IInterface)
    ['{05AC7C76-CD41-42AB-B793-1512E68D91D5}']
        procedure UpdateProgressParameters(Min, Max: Cardinal);
        procedure IncrementParameter;
    end;

implementation

end.

And I've implemented the Notify method like this:

procedure TSerialPortCommunicator.NotifyObservers;
var
    Obs: IInterface;
begin
    for Obs in FObservers do
    begin
        ISerialObserver(Obs).UpdateObserver(FReceivedData);
    end;
end;

where

FObservers: TList<IInterface>;

When NotifyObservers runs, Delphi returns an Access Violation Error.

I'd like to know what I'm doing wrong?


Solution

  • You need to cast the interface with a dynamic cast using the as operator.

    Your code, ISerialObserver(IInterface(Obs)), is a certain point of failure. You should instead write Obs as ISerialObserver. But why not make your list TList<ISerialObserver> and thus avoid the cast?

    That said, are you sure everything in your list implements ISerialObserver? It's not obvious from these excerpts. You can check for interface support with the is operator, or the rather more functional Supports() function.

    Also, you don't need to inherit from IInterface, that is implicit. So you can replace ISubject = interface(IInterface) with ISubject = interface and so on.