Building an application with the Spring4D’s IObservable<T> is pretty simple. First, we’ll create a new TBaseballGame. This one is a touch simpler:
type
TBaseballGame = class(TObservable<IDisplay>)
private
FGameInfo: TGameInfo;
protected
procedure DoNotify(const observer: IDisplay); override;
public
procedure SetInning(aInningNumber: TInningNumber; aInning: TInning);
procedure SetRuns(aRuns: TRuns);
procedure SetHits(aHits: THits);
procedure SetErrors(aErrors: TErrors);
property GameInfo: TGameInfo read FGameInfo;
end;
TBaseballGamedescends fromTObservable<IDisplay>. That class has an abstract methodDoNotifythat
needs to be overridden.TBaseballGamedoes so and thus provides a way to notify the class’s Observers that
something has changed.
procedure TBaseballGame.DoNotify(const observer: IDisplay);
begin
observer.Update(Self.GameInfo);
end;
We’ll let our observers know that an update has happened in the game in theSetInningmethod:
procedure TBaseballGame.SetInning(aInningNumber: TInningNumber; aInning: TInning);
begin
FGameInfo.Innings[aInningNumber].Top := aInning.Top; FGameInfo.Innings[aInningNumber].Bottom := aInning.Bottom; Notify;
end;
This baseball game class looks a lot like the baseball game from the previous example, except it doesn’t have any of theISubjectmethods. Instead, it descends fromTObservable<T>, which looks like this:
IObservable<T> = interface
procedure Attach(const observer: T);
procedure Detach(const observer: T);
procedure Notify;
end;
TObservable<T> = class(TInterfacedObject, IObservable<T>)
private
fLock: TMREWSync; fObservers: IList<T>;
protected
procedure DoNotify(const observer: T); virtual; abstract;
property Observers: IList<T> read fObservers;
public
constructor Create;
procedure Attach(const observer: T);
procedure Detach(const observer: T);
procedure Notify;
end;
You should see the similarities inIObservable<T>andTObservable<T> and the first demo application.
They both track observers (listeners) and they both have Subjects (TObservable).
We’ll just declare a single observer,TConsoleDisplay, which implementsIDisplay, an interface that we’ll
pass as the parameterized type (as seen above in the declaration of TBaseballGame).TConsoleDisplayis
basically declared the same way as in the first example.
type
IDisplay = interface
['{E118BD99-37BD-461C-AF69-770FD8E18702}']
procedure Update(aGameInfo: TGameInfo);
end;
TConsoleDisplay = class(TInterfacedObject, IDisplay)
procedure Update(aGameInfo: TGameInfo);
end;
The main body of the application is basically the same as the previous example:
var BaseballGame: TBaseballGame; begin BaseballGame := TBaseballGame.Create; BaseballGame.Attach(TConsoleDisplay.Create); BaseballGame.SetRuns(TRuns.Create(1, 0)); BaseballGame.SetHits(THits.Create(2, 0)); BaseballGame.SetInning(1, TInning.Create(0, 1)); ReadLn; BaseballGame.SetRuns(TRuns.Create(1, 4)); BaseballGame.SetHits(THits.Create(2, 5)); BaseballGame.SetErrors(TErrors.Create(0, 1)); BaseballGame.SetInning(4, TInning.Create(4, 0)); ReadLn; end.
Here are a couple of things to note:
• Because it takes advantage of the generic infrastructure provided by the Spring for Delphi framework, the amount of code you have to write to enable the Observer pattern goes way down.
• TBaseballGameis the subject. It takes in listeners, and then notifies them when the score changes.
• TBaseballGameis structured basically like our first demo. The data for runs, hits, and errors can be
updated at any time, and when it is, it simply calls itsNotify method.Notifyiterates over all the
observers and calls theirDoNotifymethod.
Conclusion
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 and observers can be created and added at anytime. 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.
Introduction
Many of you have traveled, I’m sure,and many of you have no doubt traveled to a country where the standard power outlet is different from the one in your home country. Here in the US, our power outlets consist of two parallel slots and a hole below them. One of the slots is “hot” with electricity, and the hole provides the ground. Countries in Europe have a different power outlet. When I go there, I have to bring a power adapter – a device that has the US output on one side and the European input on the other. I plug the adapter into the European outlet, and then plug my device – usually my computer – into the adapter. My computer’s power adapter can perform the job of converting a range of voltages – usually 110V or 220V – into something that the computer can consume. Depending on where I am in the world, my computer is using up to two adapters to power itself.
A typical power adapter
Sometimes in our code we need an adapter. Sometimes two things we want to work together don’t quite fit and we need to write a class that makes them fit. It’s the job of the “adapter” to make one interface match up with a s second one. This is called the Adapter Pattern. The purpose of the Adapter Pattern is to allow us to wrap up something to make it look and work like something it is not. Often those two things will be similar already, but they need not be. Just like our power adapter, the Adapter Pattern will allow us to take a
TSquarePegand fit it into aTRoundHole.
The Adapter Pattern’s definition is “A pattern that converts one interface into another interface expected by
a different class. The Adapter Pattern allows two disparate systems work together by providing a common interface to objects that otherwise would be incompatible.”
You’d use the Adapter Pattern when you need to use an existing class and its interface doesn’t match the interface that you need to use. An adapter will change an existing class into something expected by the consuming class.