Wer viel mit PHP zu tun gehabt hat, wird bei Delphi sicherlich dynamische Arrays vermissen, die Strings als Indizes haben. Da ich gerade an einem Projekt arbeite, bei dem der Benutzer einem Objekt einen konkreten Name-Identifier geben soll, habe ich mal eine Klasse erstellt, die einen String ein TObject zuweist. Dieses TObject kann man dann mit konkreten Instanzen einer TObject-Ableitung belegen (z.B. einer TImage-Instanz).
Delphi-Quellcode:
interface
uses
Contnrs;
type
TEasyObjectManager = class(TObject)
published
constructor Create;
destructor Destroy; override;
public
function GetValue(Name: string): TObject;
procedure SetValue(Name: string; Value: TObject);
function ValueExists(Name: string): boolean;
procedure DeleteValue(Name: string);
function Count: integer;
function GetValueById(Index: integer): TObject;
private
List: TObjectList;
end;
implementation
type
TNameObjectPair = class(TObject)
Name: string;
Value: TObject;
end;
(*** TEasyObjectManager ***)
constructor TEasyObjectManager.Create;
begin
inherited;
// OwnsObject ist false. Das heißt, die Objekte, die wir verwalten,
// werden nicht freigegeben.
List := TObjectList.Create(false);
end;
destructor TEasyObjectManager.Destroy;
begin
if Assigned(List) then List.Free;
inherited;
end;
function TEasyObjectManager.GetValue(Name: string): TObject;
var
i: integer;
begin
result := nil;
for i := 0 to List.Count-1 do
begin
if TNameObjectPair(List.Items[i]).Name = Name then
begin
result := TNameObjectPair(List.Items[i]).Value;
break;
end;
end;
end;
procedure TEasyObjectManager.SetValue(Name: string; Value: TObject);
var
i: integer;
n: TNameObjectPair;
found: boolean;
begin
found := False;
for i := 0 to List.Count-1 do
begin
if TNameObjectPair(List.Items[i]).Name = Name then
begin
TNameObjectPair(List.Items[i]).Value := Value;
found := true;
break;
end;
end;
if not found then
begin
UniqueString(Name);
n := TNameObjectPair.Create;
n.Name := Name;
n.Value := Value;
List.Add(n);
end;
end;
function TEasyObjectManager.ValueExists(Name: string): boolean;
var
i: integer;
begin
result := false;
for i := 0 to List.Count-1 do
begin
if TNameObjectPair(List.Items[i]).Name = Name then
begin
result := true;
break;
end;
end;
end;
procedure TEasyObjectManager.DeleteValue(Name: string);
var
i: integer;
begin
for i := 0 to List.Count-1 do
begin
if TNameObjectPair(List.Items[i]).Name = Name then
begin
List.Delete(i);
break;
end;
end;
end;
function TEasyObjectManager.Count: integer;
begin
result := List.Count;
end;
function TEasyObjectManager.GetValueById(Index: integer): TObject;
begin
result := List.Items[Index].Value;
end;
Ein Anwendungsbeispiel:
Delphi-Quellcode:
var
x: TEasyObjectManager;
begin
x := TEasyObjectManager.Create;
try
x.SetValue('foo', Form1); // foo wird angelegt
ShowMessage(TForm(x.GetValue('foo')).Caption);
x.SetValue('foo', Button1); // foo wird überschrieben
ShowMessage(TButton(x.GetValue('foo')).Caption);
finally
x.Free;
end;
end;
Anmerkung: Die Indizes sind natürlich case sensitive, also x.GetValue('A') ist etwas anderes als x.GetValue('a').
Count() und GetValueById() können verwendet werden, um alle Elemente der Zuordnungstabelle durchzugehen. Dies wäre dann mit einer For-Schleife möglich (In PHP würde man für diesen Zweck eine Foreach-Schleife verwenden).
Delphi-Quellcode:
var
i: integer;
begin
for i := 0 to List.Count - 1 do
begin
end;
end;
Diese Klasse müsste jedoch modifiert werden, wenn ihr Strings, Integer, Booleans oder Floats anstelle von Objekten verwalten wollt. Das wäre aber in sofern ungünstig, da dann viel rudundanter Code vorliegen würde. Ich habe mir jetzt von Java noch eine Interessante Funktionalität abgeguckt. Dort ist zwar der String ein abstrakter Datentyp, also eine Klasse, jedoch ist auch ein Integer bei Java ein einfacher Datentyp (int). Der Vorteil in Java: Weise ich ein int einem Object zu, wird dieser automatisch in eine Integer-Containerklasse gewandelt (toll!). In Delphi könnt ihr also folgende Helferklassen für meine Zuordnungsklasse verwenden:
Delphi-Quellcode:
type
TString = class(TObject)
Content: string;
end;
TInteger = class(TObject)
Content: integer;
end;
TFloat = class(TObject)
Content: float;
end;
TBoolean = class(TObject)
Content: boolean;
end;
Die Verwendung muss dann so aussehen:
MeinInteger := TInteger(x.GetValue('MeineZahl')).Content;
Wer natürlich
ausschließlich mit Integers o.ä. arbeiten will, kann natürlich meinen Code editieren und alle TObject umwandeln. Verwaltet ihr aber Strings, müssen die Values mit UniqueString() speichertechnisch einzigartig gemacht werden:
Delphi-Quellcode:
procedure TEasyStringManager.SetValue(Name: string; Value: string);
var
i: integer;
n: TNameStringPair;
found: boolean;
begin
found := False;
UniqueString(Value); // <-- Bei einer String-String Zuordnungstabelle ist diese Zeile zusätzlich nötig!
for i := 0 to List.Count-1 do
...
Für Verbesserungsvorschläge bin ich natürlich immer offen!
Gruß
blackdrake