示例:时钟 说明: ClockTimer是一个用于存储和维护一天时间的具体目标。它每秒钟通知一次它的观察者。 我们定义一个DigitalClock类来显示时间。它从一个用户界面工具箱提供的Widget类继承了它的图形功能。 代码: 迭代器uListIterator unit uListIterator; interface uses classes; type TListIterator = class private FList: TList; FCurrent: integer; public constructor Create(const AList: TList); //--- procedure First(); procedure Next(); function IsDone: Boolean; function CurrentItem: Pointer; end; implementation constructor TListIterator.Create(const AList: TList); begin FList := AList; FCurrent := 0; end; procedure TListIterator.First(); begin FCurrent := 0; end; procedure TListIterator.Next(); begin FCurrent := FCurrent + 1; end; function TListIterator.IsDone: Boolean; begin Result := FCurrent >= FList.Count; end; function TListIterator.CurrentItem: Pointer; begin if IsDone() then Result := nil else Result := FList.Items[FCurrent]; end; end. 观察者uObserver1 unit uObserver1; interface uses classes; type TSubject = class; IObserver = interface ['{7A3926C5-A58F-4FE3-9798-D1C05DB668B0}'] procedure Update(theChangedSubject: TSubject); end; TSubject = class private FObservers: TList; public constructor Create; destructor Destroy; override; //--- procedure Attach(AObserver: IObserver); procedure Detach(AObserver: IObserver); procedure Notify(); end; implementation uses uListIterator; constructor TSubject.Create; begin inherited; //--- FObservers := TList.Create; end; destructor TSubject.Destroy; begin FObservers.Free; //--- inherited; end; procedure TSubject.Attach(AObserver: IObserver); begin FObservers.Add(Pointer(AObserver)); end; procedure TSubject.Detach(AObserver: IObserver); begin FObservers.Remove(Pointer(AObserver)); end; procedure TSubject.Notify(); var AIterator: TListIterator; begin AIterator := TListIterator.Create(FObservers); try with AIterator do begin First; while not IsDone() do begin IObserver(CurrentItem).Update(Self); Next(); end; end; finally AIterator.Free; end; end; end. 时钟uClock unit uClock; interface uses SysUtils, Classes, Graphics, Controls, ExtCtrls, DateUtils, uObserver1; type TClockTimer = class(TSubject) private FTimer: TTimer; FTime: TDateTime; procedure DoTimer(Sender: TObject); public constructor Create; destructor Destroy; override; //--- function GetHour(): integer; function GetMinute: integer; function GetSecond: integer; procedure Tick(); end; TWidget = class(TGraphicControl) protected procedure Paint; override; public procedure Draw(); virtual; abstract; end; TDigitClock = class(TWidget, IObserver) private FSubject: TClockTimer; public constructor Create(AOwner: TComponent; const ASubject: TClockTimer); reintroduce; destructor Destroy; override; //--- procedure Draw(); override; procedure IObserver.Update = IUpdate; procedure IUpdate(theChangedSubject: TSubject); end; TAnalogClock = class(TWidget, IObserver) private FSubject: TClockTimer; public constructor Create(AOwner: TComponent; const ASubject: TClockTimer); reintroduce; destructor Destroy; override; //--- procedure Draw; override; procedure IObserver.Update = IUpdate; procedure IUpdate(theChangedSubject: TSubject); end; implementation constructor TClockTimer.Create; begin inherited; //--- FTimer := TTimer.Create(nil); with FTimer do begin Interval := 1000; OnTimer := self.DoTimer; Enabled := True; end; end; destructor TClockTimer.Destroy; begin FTimer.Free; //--- inherited; end; function TClockTimer.GetHour(): integer; begin Result := HourOf(FTime); end; function TClockTimer.GetMinute: integer; begin Result := MinuteOf(FTime); end; function TClockTimer.GetSecond: integer; begin Result := SecondOf(FTime); end; procedure TClockTimer.Tick(); begin FTime := Now; //--- self.Notify(); end; procedure TClockTimer.DoTimer(Sender: TObject); begin self.Tick; end; constructor TDigitClock.Create(AOwner: TComponent; const ASubject: TClockTimer); begin inherited Create(AOwner); //--- FSubject := ASubject; FSubject.Attach(self); end; destructor TDigitClock.Destroy; begin FSubject.Detach(self); //--- inherited; end; procedure TDigitClock.IUpdate(theChangedSubject: TSubject); begin if theChangedSubject = FSubject then self.Draw(); end; procedure TDigitClock.Draw(); var AText: string; AHour, AMinute, ASecond: Integer; begin with FSubject do begin AHour := GetHour(); AMinute := GetMinute(); ASecond := GetSecond(); end; AText := Format('%d:%d:%d', [AHour, AMinute, ASecond]); //--- with self.Canvas do begin with Brush do begin Color := clBlack; Style := bsSolid; end; FillRect(self.ClientRect); //--- with Font do begin Color := clRed; Size := 10; end; with TextExtent(AText) do TextOut((Self.Width - cX) div 2, (self.Height - cY) div 2, AText); end; end; procedure TWidget.Paint; begin self.Draw; end; constructor TAnalogClock.Create(AOwner: TComponent; const ASubject: TClockTimer); begin inherited Create(AOwner); //--- FSubject := ASubject; FSubject.Attach(self); end; destructor TAnalogClock.Destroy; begin FSubject.Detach(self); //--- inherited; end; procedure TAnalogClock.Draw; var AText: string; AHour, AMinute, ASecond: Integer; begin with FSubject do begin AHour := GetHour(); AMinute := GetMinute(); ASecond := GetSecond(); end; AText := Format('%d:%d:%d', [AHour, AMinute, ASecond]); //--- with self.Canvas do begin with Brush do begin Color := clBlack; Style := bsSolid; end; FillRect(self.ClientRect); //--- with Font do begin Color := clYellow; Size := 10; end; with TextExtent(AText) do TextOut((Self.Width - cX) div 2, (self.Height - cY) div 2, AText); end; end; procedure TAnalogClock.IUpdate(theChangedSubject: TSubject); begin if theChangedSubject = FSubject then self.Draw(); end; end. 测试 unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, uClock, ExtCtrls; type TForm1 = class(TForm) procedure FormDestroy(Sender: TObject); procedure FormCreate(Sender: TObject); private FTimer: TClockTimer; FDigitClock: TDigitClock; FAnalogClock: TAnalogClock; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.FormCreate(Sender: TObject); begin FTimer := TClockTimer.Create; //--- FDigitClock := TDigitClock.Create(nil, FTimer); with FDigitClock do begin Parent := Self; Top := 10; Left := 10; Width := 100; Height := 30; end; //--- FAnalogClock := TAnalogClock.Create(nil, FTimer); with FAnalogClock do begin Parent := Self; Top := 60; Left := 10; Width := 100; Height := 30; end; end; procedure TForm1.FormDestroy(Sender: TObject); begin FAnalogClock.Free; FDigitClock.Free; FTimer.Free; end; end.