The Observer pattern in Delphi extends the basic Observer pattern. For more information on the Observer mode, please refer to [Gam+, pages 293..303]
Define a one-to-many dependency relationship between objects. When the state of an object changes, all objects that depend on it are notified and automatically updated.
Splitting a system into a series of cooperating classes has certain side effects: consistency between related objects must be protected. We don't want to tightly couple types for the sake of dimensional consistency, because this reduces their reusability. [Gam+,p293].
Delphi's events (actual method addresses) allow you to have a good structure for handling these problems. Events allow you to eliminate coupling and achieve better coupling. For example: the event TButton.OnClick is dispatched to complete related work. But the class does not save a reference to the event handler. In the observer pattern, the class that dispatches the event is called the target object (subject), and the class that controls the event is called the observer (observer)
The events in Delphi can better eliminate the coupling of classes. If you want to control multiple events and refer to the observer mode, you can establish a one-to-many notification mechanism. A target can have any number of observers. All observers receive notifications when the target's state changes. After the observer receives the notification, it immediately queries the target object to maintain synchronization with the target object.
This interaction is also called publish-subscribe, and the target is the publisher of the notification. It does not need to know who its observers are when it discovers a notification. Any number of observers can subscribe and receive notifications.
This observer mode application will bring you the advantages of Delphi event mechanism in handling class coupling. One-to-many structures register observers through registering and un-registering. The one-to-many mechanism is actually applied on the basis of iterators.
Suppose you have a Tsubject class that defines meaningful behavior. Let’s first look at a demo code of observer mode:
type
TSubject = class (TObject)
PRivate
FObservers: TList;
public
procedure RegisterObserver(Observer: TSubjectObserver);
procedure UnregisterObserver(Observer: TSubjectObserver);
end;
TSubjectObserver = class (TComponent)
private
FEnabled: Boolean;
published
property Enabled: Boolean read FEnabled write FEnabled; default True;
end;
Among the above interfaces:
? A registration mechanism for registering observers for Tsubject.
¨ FObservers: TList; stores registered observers.
¨ RegisterObserver(..) is used to register observers and add them to Fobservers.
¨ UnregisterObserver(..) is used to unregister the observer and remove related objects from Fobservers.
?The observer mode also needs to create a new class TsubjectObserver
¨ This class is the descendant of Tcomponent.
¨ .An Enabled property sets the observation on or off. .
The actual application of the following observer mode:
procedure TSubject.RegisterObserver(Observer: TSubjectObserver);
begin
if FObservers.IndexOf(Observer) = -1 then
FObservers.Add(Observer);
end;
procedure TSubject.UnregisterObserver(Observer: TSubjectObserver);
begin
FObservers.Remove(Observer);
end;
The implementation of Shangguan supports the registration part of observers. Where is the one-to-many notification mechanism? For actual one-to-many notification applications, you can define a Change method for Tsubject to notify its registered observers, and the observers can define an OnChange event attribute to handle scheduling. The code is as follows:
type
TSubject = class (TObject)
private
FObservers: TList;
protected
» procedure Change; {Call this method to dispatch notification}
public
procedure RegisterObserver(Observer: TSubjectObserver);
procedure UnregisterObserver(Observer: TSubjectObserver);
end;
TSubjectObserver = class (TComponent)
private
FEnabled: Boolean;
» FOnChange: TNotifyEvent;
protected
» procedure change;
published
property Enabled: Boolean read FEnabled write FEnabled;
» property OnChange: TNotifyEvent read FOnChange write FOnChange;
end;
implementation
procedureTSubject.Change;
var
» Obs: TSubjectObserver;
» I: Integer;
begin
» for I := 0 to FObservers.Count - 1 do
» begin
» Obs := FObservers[I];
» if Obs.Enabled then Obs.Change;
» end;
end;
procedure TSubject.RegisterObserver(Observer: TSubjectObserver);
begin
if FObservers.IndexOf(Observer) = -1 then
FObservers.Add(Observer);
end;
procedure TSubject.UnregisterObserver(Observer: TSubjectObserver);
begin
FObservers.Remove(Observer);
end;
procedureTSubjectObserver.Change;
begin
» if Assigned(FOnChange) then FOnChange(Self);
end;
In the above implementation code:
? Tsubject's Change method iterates over all registered observers and calls the Change method of each observer, an implementation of a one-to-many notification.
? The Enabled property of the observer determines whether it is or receives notifications
? The OnChange event of TsubjectObserver actually handles synchronization and other operations.
Organizing
//Many excerpts from "Design Patterns"