Newsgroup: it.comp.lang.delphi
Titolo: [LUNGO] Versione definitiva dela lista type-safe senza duplicati

Per (s)kiarirmi meglio le idee dopo il 3ad "Lista type-safe senza duplicati: 
e in modifica, che succede?" ho provato a implementare una lista (TMyList) 
che si occupa di garantire che tutti i suoi elementi (TMyItem), oltre a 
essere distinti, abbiano anche un nome (la proprietà Name) diverso. 
Ho usato un meccanismo di notifica mediante eventi (TChangeEvent).
Il codice per provarla è nella seconda unit più sotto (basta sostituirlo 
integralmente a quello di una nuova form vuota).
(critiche e commenti sono i benvenuti)
=============CODICE DELLA LISTA======================
unit Unit2;
interface
uses
  Classes, Contnrs, SysUtils;
type
  TMyList = class;
  TMyItem = class;
  TChangeEvent = procedure(Sender: TMyItem; const s: string) of object;
  TMyItem = class
  private
    FName: string;
    FOnChange: TChangeEvent;
    procedure SetName(const Value: string);
    procedure DoChange(const s: string);
  public
    property Name: string read FName write SetName;
    property OnChange: TChangeEvent read FOnChange write FOnChange;
  end;
  TMyList = class
  private
    FList: TObjectList;
    function Find(const AName: string): Boolean;
    function GetItems(i: Integer): TMyItem;
    procedure SetItems(i: Integer; const Value: TMyItem);
    procedure ChangeEvent(Item: TMyItem; const Value: string);
  public
    constructor Create;
    destructor Destroy; override;
    function Add(Item: TMyItem): Integer;
    procedure Clear;
    procedure Delete(Item: TMyItem);
    //mancano IndexOf e altre
    procedure GetStrings(Strings: TStrings);
    property Items[i: Integer]: TMyItem read GetItems write SetItems; 
default;
  end;
  EArchiveDuplicate = class(Exception);
implementation
uses
  DIALOGS, Unit1;
{ TMyList }
function TMyList.Add(Item: TMyItem): Integer;
begin
  if Find(Item.Name) then
    raise EArchiveDuplicate.Create('ERRORE: si sta tentando di aggiungere un 
nuovo elemento di nome ' +
      QuotedStr(Item.Name) + ', ma questo nome esiste già nella lista.')
  else
    begin
      Form1.AddInfo('un elemento di nome ' +
        QuotedStr(Item.Name) + ' sta per essere aggiunto alla lista');
      Result:= FList.Add(Item);
      Item.OnChange:= ChangeEvent;
    end
end;
procedure TMyList.ChangeEvent(Item: TMyItem; const Value: string);
begin
  Form1.AddInfo('l''elemento numero ' +
    IntToStr(Flist.IndexOf(Item)) + ' sta per cambiare nome: da ' +
      QuotedStr(Item.Name) + ' a ' + QuotedStr(Value));
  if Find(Value) then
    raise EArchiveDuplicate.Create('ERRORE: non si può cambiare nome 
all''elemento numero ' +
    IntToStr(Flist.IndexOf(Item)) + ' perchè ' + QuotedStr(Value) +' esiste 
già: ' +
    ' il nome dell''elemento n. ' + IntToStr(Flist.IndexOf(Item)) + ' resta 
' +
    QuotedStr(Item.Name));
end;
procedure TMyList.Clear;
begin
  FList.Clear;
end;
constructor TMyList.Create;
begin
  FList:= TObjectList.Create(True);
end;
procedure TMyList.Delete(Item: TMyItem);
var
  i: Integer;
begin
  i:= FList.IndexOf(Item);
  if i > -1 then
    begin
      Form1.AddInfo('L''elemento n. ' + IntToStr(i) + ' di nome ' +
        QuotedStr(Item.Name) + ' sta per essere eliminato');
      FList.Delete(i);
    end
  else
    Form1.AddInfo('si è cercato di cancellare dalla lista un elemento ' +
      'che non esiste');
end;
destructor TMyList.Destroy;
begin
  FList.Free;
  inherited Destroy;
end;
function TMyList.Find(const AName: string): Boolean;
var
  i: Integer;
begin
  Result:= False;
  for i:= 0 to Pred(FList.Count) do
    if (FList[i] as TMyItem).Name = AName then
    begin
      Result:= True;
      Break;
    end;
end;
function TMyList.GetItems(i: Integer): TMyItem;
begin
  Result:= FList[i] as TMyItem;
end;
procedure TMyList.GetStrings(Strings: TStrings);
var
  i: Integer;
begin
  for i:= 0 to Pred(FList.Count) do
    Strings.Add((FList[i] as TMyItem).Name)
end;
procedure TMyList.SetItems(i: Integer; const Value: TMyItem);
begin
  if FList[i] <> Value then
    if FList.IndexOf(Value) > -1 then
      raise EArchiveDuplicate.Create('ERRORE: Si sta tentando di aggiungere 
' +
        'un elemento duplicato dal nome ' + QuotedStr(Value.Name));
  begin
    Form1.AddInfo('l''elemento n. ' + IntToStr(i) +
      ' sta per essere sostituito con un altro elemento, di nome ' + 
Value.Name);
    FList[i]:= Value;
  end;
end;
{ TMyItem }
procedure TMyItem.DoChange(const s: string);
begin
  if Assigned(FOnChange) then
    FOnChange(Self, s);
end;
procedure TMyItem.SetName(const Value: string);
begin
  if Trim(UpperCase(FName)) <> Trim(UpperCase(Value)) then
  begin
    DoChange(Value);
    FName:= Value;
  end;
end;
end.
========================FINE CODICE DELLA LISTA=======================
================INIZIO CODICE DELLA FORM DI PROVA=====================
unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;
type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    FMemo, FMemoItems: TMemo;
  public
    procedure AddInfo(const s: string);
  end;
var
  Form1: TForm1;
implementation
uses Unit2;
{$R *.dfm}
procedure TForm1.AddInfo(const s: string);
begin
  FMemo.Lines.Add(s);
  FMemo.Lines.Add('>---------------');
end;
procedure TForm1.FormCreate(Sender: TObject);
var
  TheList: TMyList;
  Item1, Item2, Item3: TMyItem;
begin
  FMemo:= TMemo.Create(Self);
  FMemoItems:= TMemo.Create(Self);
  with FMemo do
  begin
    Width:= Round(Self.Width * 0.8);
    Align:= alLeft;
    ScrollBars:= ssVertical;
    Anchors:= [akLeft, akTop, akBottom, akRight];
    Parent:= Self;
  end;
  with FMemoItems do
  begin
    Align:= alClient;
    ScrollBars:= ssVertical;
    Parent:= Self;
  end;
  try
    try
      TheList:= TMyList.Create;
      Item1:= TMyItem.Create;
      Item2:= TMyItem.Create;
      Item3:= TMyItem.Create;
      Item1.Name:= 'alpha';
      Item2.Name:= 'beta';
      Item3.Name:= 'beta';
      TheList.Add(Item1);
      TheList.Add(Item2);
      Item1.Name:= 'beta';
    except
      on E: Exception do
      begin
        AddInfo(E.Message);
        try
          TheList.Add(Item3);
        except
          on E: Exception do
          begin
            AddInfo(E.Message);
            try
              Item3.Name:= 'gamma';
              TheList.Add(Item3);
              TheList.Delete(Item3);
            except
            end;
          end
        end
      end
    end
  finally
    FMemoItems.Clear;
    TheList.GetStrings(FMemoItems.Lines);
    FreeAndNil(TheList);
  end
end;
end.
==========================FINE CODICEDELLA FORM DI PROVA=========
-- 
Mauro Falzari ( 
http://digilander.libero.it/mauro.falzari
 )
"Se guardi nell'abisso, anche l'abisso guarda in te." (Friedrich Nietzsche)

 duplicati: e in modifica, che succede?" 
(..su libero.delphi di Marco Cantų)
