《GOF设计模式》—观察者(OBSERVER)—Delphi源码示例:时钟

示例:时钟
说明:
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
 
clip_image002
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.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值