Delphi-PRAXiS
Seite 1 von 3  1 23   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Fluent Design und Records (https://www.delphipraxis.net/201758-fluent-design-und-records.html)

hschmid67 23. Aug 2019 06:31

Fluent Design und Records
 
Liebe Delphi-Gemeinde,

ich mag im Design meiner Objekte das Pattern des Fluent Design sehr gerne und gestalte meine Methoden deshalb gerne damit. Ich meine damit also etwa ein solches Gebilde:

Delphi-Quellcode:
Result := CreateSomeInterface.DoSomething('withParameter').DoSomethingOther.ConvertEverythingToString;


Das ist an manchen Stellen sehr praktisch und macht den Code in meinen Augen etwas schöner, vor allem, wenn man mit Interfaces statt mit Objekten arbeitet.

Nun frage ich mich, ob man das auch mit Records machen kann, bzw. ob das sinnvoll ist.

Angenommen ich habe folgendes:

Delphi-Quellcode:
type
  Tfluent = record
    variable: string;
    function DoSomething(const mParameter: string): Tfluent;
  end;

function Tfluent.DoSomething(const mParameter: string): Tfluent;
begin
  variable := variable + mParameter;
  Result := Self;
end;
Soweit ich das verstehe, würde das
Delphi-Quellcode:
Result := Self;
bei Records immer dazu führen, dass der komplette Record kopiert wird, da eine Übergabe bei Records ja "als Wert" und nicht "als Zeiger" funktioniert.

Damit wäre das Fluent Design bei Records nicht sinnvoll und würde ständig eine Kopiererei der Daten verursachen. Ist das so, oder gibt es einen Trick? Wie macht ihr das?

Ich fände die Records deshalb sehr schön, weil man z.B. mit Operator Overloading sich dann eine Methode "ConvertEverthingToString" sparen könnte, was meines Wissens mit Objekten/Interfaces bislang noch nicht geht.

Viele Grüße
Harald

Redeemer 23. Aug 2019 07:51

AW: Fluent Design und Records
 
Man kann einen Record erstellen, der als einzige Methoden Konstruktoren hat. Das ist natürlich Quatsch, würde aber vielleicht funktionieren. Ich setze schon mal einen Helm auf, weil ich gleich gesteinigt werde.

uligerhardt 23. Aug 2019 08:00

AW: Fluent Design und Records
 
Du könntest jeweils einen Zeiger auf Self zurückgeben. Also Result := @Self (mit Klammeraffe).
Da Delphi erlaubt, beim Dereferenzieren den ^ wegzulassen, könnten die Aufrufe sogar identisch ausschauen.
(Wobei ich dieses Feature persönlich verabscheue. Aber die Geschmäcker sind verschieden.)

Mavarik 23. Aug 2019 10:46

AW: Fluent Design und Records
 
Eigentlich hat uligerhardt schon alles gesagt...

Ich würde jedoch das ^ nie weglassen... Einfach um den Ursprung besser zu verstehen.

uligerhardt 23. Aug 2019 10:51

AW: Fluent Design und Records
 
Zitat:

Zitat von Mavarik (Beitrag 1442735)
Ich würde jedoch das ^ nie weglassen... Einfach um den Ursprung besser zu verstehen.

:thumb:

Stevie 23. Aug 2019 12:56

AW: Fluent Design und Records
 
Ihr meint sicher Fluent Interface und nicht Fluent Design.

hschmid67 23. Aug 2019 13:52

AW: Fluent Design und Records
 
Zitat:

Ihr meint sicher Fluent Interface und nicht Fluent Design.
Oh, natürlich meinte ich Fluent Interface :oops: - Danke für die Klarstellung.

Und vielen Dank auch an alle, die sich bisher beteiligt hatten. Hmmm, das mit der Adresse und dem ^ ist eine Lösung, aber irgendwie mag ich solche Operatoren in meinem normalen Code nicht - das sieht für mich immer nach Eingriff auf unterster Ebene aus. Und das ist in einer Bibliothek ok, aber für den täglichen Gebrauch... Ob ich dann wohl doch lieber bei den Interfaces bleibe?

Viele Grüße
Harald

uligerhardt 24. Aug 2019 13:51

AW: Fluent Design und Records
 
Zitat:

Zitat von hschmid67 (Beitrag 1442783)
Hmmm, das mit der Adresse und dem ^ ist eine Lösung, aber irgendwie mag ich solche Operatoren in meinem normalen Code nicht - das sieht für mich immer nach Eingriff auf unterster Ebene aus. Und das ist in einer Bibliothek ok, aber für den täglichen Gebrauch... Ob ich dann wohl doch lieber bei den Interfaces bleibe?

Mit dem Haken siehst du halt, dass du dereferenzierst. Bei Variablen von Klassen- oder Interfacetypen dereferenzierst du genau so, nur ist es versteckt. De facto ist die zweite Variante also sogar weniger klar. :wink: (Vom erhöhten Overhead (dynamische Allozierung, virtuelle Methodenaufrufe) ganz zu schweigen.)

hschmid67 24. Aug 2019 15:36

AW: Fluent Design und Records
 
Hallo Zusammen,

jetzt habe ich den Vorschlag von uligerhardt mal ausprobiert, aber irgendwas scheine ich nicht richtig zu verstehen. Könnt Ihr mir nochmal weiterhelfen?

Also, ich hab mal folgende Unit gemacht:

Delphi-Quellcode:
unit hs.str2;

interface

type
  ThsStr2 = record
    FStr: string;
    function AsString: string;
    function Init(const mString: string): ThsStr2;
  end;

implementation

uses
  System.SysUtils;

{ ThsStr2 }

function ThsStr2.AsString: string;
begin
  Result := FStr;
end;

function ThsStr2.Init(const mString: string): ThsStr2;
begin
  FStr := mString;
//  Result := @Self; // so war der Vorschlag, aber das kompiliert gar nicht "Pointer und ThsStr2"
  Result := ThsStr2(@Self); // so kompiliert es, aber wirft eine AV bei der Ausführung
end;

end.
Testen wollte ich das Ganze so:

Delphi-Quellcode:
procedure Test;
var
  lStr: ThsStr2;
  lDummy: string;
begin
  lDummy := lStr.Init('dummy').AsString;
end;
Aber eben beim Init bekomme ich eine AV. Was mache ich falsch - oder wo ist mein Denkfehler?

Viele Grüße
Harald

uligerhardt 24. Aug 2019 15:42

AW: Fluent Design und Records
 
Sorry, ich hab's etwas kurz erklärt. :oops:
Du musst einen Zeigertyp zurückgeben, also etwas so:
Delphi-Quellcode:
type
  PhsStr2 = ^ThsStr2; // Zeiger auf ThsStr2
  ThsStr2 = record
    FStr: string;
    function AsString: string;
    function Init(const mString: string): PhsStr2; // <== Beachte den Rückgabetyp!
  end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:24 Uhr.
Seite 1 von 3  1 23   

Powered by vBulletin® Copyright ©2000 - 2022, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2021 by Daniel R. Wolf