Zugegeben, die Überschrift ist etwas zugespitzt formuliert, es soll zur Diskussion anregen. Starten wir mit Bekanntem. Gegeben ist die Situation: Arbeit mit einem Geschäftsobjekt (Business Object).
1) Die Definition sieht wie folgt aus:
Delphi-Quellcode:
type
TPerson = class(TObject)
private
FID: TID;
FVorname: String;
FNachname: String;
function GetCaption: String;
public
constructor Create(pmID: TID); reintroduce;
property Caption: String // Format: Nachname, Vorname
read GetCaption;
property ID: TID
read FID;
property Vorname: String
read FVorname write FVorname;
property Nachname: String
read FNachname write FNachname;
end;
type
TdmDaten = class(TDataModule)
public
function GetPerson(pmPersonID: TID): TPerson;
end;
function TdmDaten.GetPerson(pmPersonID: TID): TPerson;
begin
if IsValidID(pmPersonID) then
Result := FPersonList.Find(pmPersonID)
else
Result := Nil;
end;
Angewendet wie folgt:
Delphi-Quellcode:
var person: TPerson := dmDaten.GetPerson(idPerson);
if person <> Nil
name := person.Caption
else
name := 'John Doe';
2) In der nächsten Überarbeitung erweitern wir das Datenmodul:
Delphi-Quellcode:
type
TdmDaten = class(TDataModule)
public
...
function GetPersonCaption(pmPersonID: TID): String;
end;
function TdmDaten.GetPersonCaption(pmPersonID: TID): String;
begin
var person: TPerson := GetPerson(pmID);
if person <> Nil then
Result := person.Caption
else
Result := 'John Doe';
end;
Jetzt ist es deutlich komfortabler in der Anwendung:
name := dmDaten.GetPersonCaption(idPerson);
In der realen Welt kann ein Geschäftsobjekt viele Eigenschaften haben. Nicht alle kann/will man über einen Direktzugriff zugänglich machen. Damit wären wir wieder am Anfang und beim ersten Beispiel.
3) Was wäre, wenn es
immer ein Objekt gibt. Wenn kein reales vorhanden ist, dann auf Wunsch ein Fake-Objekt. Es könnte wie folgt aussehen:
Delphi-Quellcode:
type
TPerson = class(TObject)
public
function IsFake: Boolean;
...
end;
TdmDaten = class(TDataModule)
public
function GetPerson(pmPersonID: TID; pmFakeReturn: Boolean = False): TPerson;
...
end;
function TPerson.IsFake: Boolean;
begin
Result := (Self = __FakePerson);
end;
function TdmDaten.GetPerson(pmPersonID: TID; pmFakeReturn: Boolean): TPerson;
begin
Result := Nil;
if IsValidID(pmPersonID) then
Result := FPersonList.Find(pmPersonID);
if (Result = Nil) and pmFakeReturn then
Result := __FakePerson;
end;
initialization
__FakePerson := TPerson.Create(0);
__FakePerson.Vorname := 'John';
__FakePerson.Nachname := 'Doe';
finalization
__FakePerson.Free;
Der Zugriff wie folgt:
name := dmDaten.GetPerson(idPerson, True).Caption;
Diese Schreibweise sieht elegant aus, beinhaltet aber auch Gefahren. Allerdings nichts, was bei disziplinierter Programmierung ein Problem sein sollte. Zur Zeit arbeite ich mit Fall 1), 2) und anderen Techniken. Gebe aber zu, der Ansatz mit dem Fake-Objekt hat einen gewissen Charme und schwirrt im Kopf herum. Im Anhang der Sourcecode zum Spielen.
Nachtrag: Die Bezeichnung Fake-Objekt scheint zu unpräzise. Dahinter kann sich auch ein Default-Objekt verbergen.
Delphi-Quellcode:
type
TDefaultPerson = class(TPerson)
protected
function GetCaption: String; override;
end;
function TDefaultPerson.GetCaption: String;
begin
if DayOfWeek(Date) = 2 then // I don't like monday
Result := Format('%s, %s', ['Lecter', 'Hannibal'])
else
Result := inherited GetCaption;
end;
Ich habe das Beispiel angepasst.
Bis bald...
Thomas