unit uObjects;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons, ExtCtrls;

type
  TMyNotification = (cnAdded, cnExtracting, cnDeleting);

  TItem = class;

  IMonitorNotify = interface
    ['{4B30BE70-0E18-4505-B263-F3DC82C7D705}']
    function GetMessages : TStringList;
    procedure Notification(AnObject: TItem; Operation: TMyNotification);
  end;

  TMonitor = class(TInterfacedObject, IMonitorNotify)
  private
    FMsg : TStringList;
  public
    Destructor Destroy; override;
    function GetMessages : TStringList;
    procedure Notification(AnObject: TItem; Operation: TMyNotification);
  end;


  TItem = class(TObject)
  private
    FID : String;
  public
    Constructor Create; overload;
    Constructor Create(const FID : String); overload;
    function ToString : String;
  end;

  TDemoDP = class(TObject)
  private
    FList : TStringList;
    FMonitor : TMonitor;

    procedure FreeAllItems;
  protected
    procedure Added(var Item: TItem); virtual;
    procedure Deleting(var Item: TItem); virtual;
    function Remove(var Item: TItem) : TItem; virtual;
    function GetMonitor : IMonitorNotify;
  public
    Constructor Create;
    Destructor Destroy; override;

    procedure Notify(Item: TItem; Action: TMyNotification); virtual;
    function FindItem(const sID : String) : TItem;
    function GetMonitorMessages : String;
  end;

implementation

{ TItem }

constructor TItem.Create(const FID: String);
begin
  Self.FID := FID;
end;

constructor TItem.Create;
begin
  FID := '';
end;

function TItem.ToString: String;
begin
  Result := FID;
  if (Result = '') then
  begin
    Result := IntToStr(Trunc(Now * 1000000));
    FID := Result;
  end;
end;

{ TDemoDP }

procedure TDemoDP.Added(var Item: TItem);
begin
  FList.AddObject(Item.ToString, Item);
  GetMonitor.Notification(Item, cnAdded);
end;

constructor TDemoDP.Create;
begin
  FList := TStringList.Create;
  FMonitor := TMonitor.Create;
  FMonitor._AddRef;
end;

procedure TDemoDP.Deleting(var Item: TItem);
var
  idx : Integer;
  aItem : TItem;
begin
  idx := FList.IndexOf(Item.ToString);
  if (idx <> -1) then
  begin
    aItem := TItem(FList.Objects[idx]);
    FList.Delete(idx);
    GetMonitor.Notification(Item, cnDeleting);
    FreeAndNil(aItem);
  end;
end;

destructor TDemoDP.Destroy;
begin
  FreeAllItems;
  FreeAndNil(FList);
  FMonitor._Release;
  inherited;
end;

function TDemoDP.FindItem(const sID: String) : TItem;
var
  idx : Integer;
begin
  Result := nil;
  idx := FList.IndexOf(sID);
  if (idx <> -1) then
    Result := TItem(FList.Objects[idx]);
end;

procedure TDemoDP.FreeAllItems;
var
  iCount : Integer;
  aItem : TItem;
begin
  for iCount := FList.Count - 1 downto 0 do
  begin
    aItem := TItem(FList.Objects[iCount]);
    FreeAndNil(aItem);
  end;
end;

function TDemoDP.GetMonitor : IMonitorNotify;
begin
  Result := FMonitor as IMonitorNotify;
end;

function TDemoDP.GetMonitorMessages: String;
begin
  Result := GetMonitor.GetMessages.Text;
end;

procedure TDemoDP.Notify(Item: TItem; Action: TMyNotification);
begin
  if (Item = nil) then
    Exit;
  case Action of
    cnAdded: Added(Item);
    cnDeleting: Deleting(Item);
    cnExtracting : Remove(Item);
  end;
end;

function TDemoDP.Remove(var Item: TItem): TItem;
var
  idx : Integer;
  aItem : TItem;
begin
  Result := nil;
  idx := FList.IndexOf(Item.ToString);
  if (idx <> -1) then
  begin
    aItem := TItem(FList.Objects[idx]);
    FList.Delete(idx);
    Result := aItem;
    GetMonitor.Notification(Item, cnExtracting);
  end;
end;

{ TMonitor }

destructor TMonitor.Destroy;
begin
  FreeAndNil(FMsg);
  inherited;
end;

function TMonitor.GetMessages: TStringList;
begin
  Result := FMsg;
end;

procedure TMonitor.Notification(AnObject: TItem;
  Operation: TMyNotification);
var
  sData : String;
begin
  if (FMsg = nil) then
    FMsg := TStringList.Create;

  case Operation of
    cnAdded: sData := '在' + DateTimeToStr(Now) + ' 加入';
    cnDeleting: sData := '在' + DateTimeToStr(Now) + ' 删除';
    cnExtracting : sData := '在' + DateTimeToStr(Now) + ' 移除';
  end;

  FMsg.Add(AnObject.ToString + ':' + sData);
end;

end.
