Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Interfaces, Verwenden von Gettern (https://www.delphipraxis.net/196850-interfaces-verwenden-von-gettern.html)

Rollo62 25. Jun 2018 14:27

Interfaces, Verwenden von Gettern
 
Hallo zusammen,

mir fällt beim Testen Folgendes in den FMX Sourcen auf:

Delphi-Quellcode:
  IBrushObject = interface(IFreeNotificationBehavior)
    ['{BB870DB6-0228-4165-9906-CF75BFF8C7CA}']
    function GetBrush: TBrush;                            // A.) Hier wird ein Getter vorausgesetzt
    property Brush: TBrush read GetBrush;
  end;

  TBrushObject = class(TFmxObject, IBrushObject)
  private
    FBrush: TBrush;
    { IBrushObject }
    function GetBrush: TBrush;              // B.) Der Getter wird hier definiert, Result := FBrush;
  protected
    procedure SetName(const NewName: TComponentName); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Brush: TBrush read FBrush write FBrush;  // C.) Hier wird direkt auf das Feld zugegriffen
  end;
Ich würde im Design oben IMMER den entsprechenden Getter verwenden, auch bei C.).

Jetzt frage ich mich ob die EMBA C.) Variante evtl. irgendeinen einen Vorteil hat ?
(Ist vielleicht schneller, weil inline und der Getter entfällt).

Ist C.) überhaupt ein sauberes Klassendesign ?
Meiner Meinung nach eher nicht, weil es zwei Arten des Zugriffs gibt.

Rollo

mkinzler 25. Jun 2018 14:33

AW: Interfaces, Verwenden von Gettern
 
Der Getter bringt hier m.M. nach keinen Vorteil.

stahli 25. Jun 2018 14:36

AW: Interfaces, Verwenden von Gettern
 
Ich kann mir nicht vorstellen, dass da ein Konzept oder Plan dahinter steckt.

Ehrlich hätte ich erwartet, dass der Compiler das gar nicht akzeptiert.

Ich halte das für unsauberen Code. Selbst wenn das eine halbe Millisekunde spart wiegt das nicht die Probleme auf, die eine solche Unordnung möglicherweise schafft.

mkinzler 25. Jun 2018 14:42

AW: Interfaces, Verwenden von Gettern
 
Warum sollte der Compiler das nicht akzeptieren? Ist eine "normale" Funktion und eine Property mit Direktzugriff auf die private Variable. Aus dem Namen könnte man die Absicht ableiten, der Compiler aber nicht.

Uwe Raabe 25. Jun 2018 14:49

AW: Interfaces, Verwenden von Gettern
 
Zitat:

Zitat von stahli (Beitrag 1405758)
Ich kann mir nicht vorstellen, dass da ein Konzept oder Plan dahinter steckt.

Das vermute ich auch.

Zitat:

Zitat von stahli (Beitrag 1405758)
Ehrlich hätte ich erwartet, dass der Compiler das gar nicht akzeptiert.

Syntaktisch ist das durchaus in Ordnung und kann ja sogar auch beabsichtigt sein, wenn beim Zugriff über das Interface etwas anderes passieren soll, als beim Zugrüff über das Streaming-System.

Zitat:

Zitat von stahli (Beitrag 1405758)
Ich halte das für unsauberen Code. Selbst wenn das eine halbe Millisekunde spart wiegt das nicht die Probleme auf, die eine solche Unordnung möglicherweise schafft.

Wie gesagt, auch wenn es hier vermutlich nicht so ist, kann so ein Konstrukt auch beabsichtigt sein und im anderen Fall nicht das gewünschte Ergebnis liefern.

Folgendes Szenario wäre hypothetisch denkbar:
Nehmen wir an, das Feld wäre nil, dann würde das so auch in der DFM/FMX gespeichert und auch so wieder gelesen. Der Getter könnte in diesem Fall aber automatisch eine Default-Instanz erzeugen, damit der nil-Fall bei Interface-Zugriff niemals auftritt.

Würde das Property immer den Getter verwenden, würde die Default-Instanz in der DFM/FMX gespeichert und wäre somit nicht mehr default.

Stevie 25. Jun 2018 15:56

AW: Interfaces, Verwenden von Gettern
 
Das ist mal wieder der Tatsache geschuldet, dass Properties in Delphi technisch nur halbherzig eine Kapselung darstellen.

Aus OOP und Codesicht habe ich durch eine Eigenschaft in Delphi eine Kapselung hergestellt - also wenn ich auf der konsumierenden Seite auf eine Eigenschaft zugreife, dann kann ich in der implementierenden Klasse, direkt auf die Feldvariable oder über einen Setter wer weiß was machen, ohne dass davon die konsumierende Seite etwas mitbekommen muss oder ich Code anpassen muss.

ABER: Durch die Art der Implementierung (auf der konsumierenden Seite baut der Compiler entsprechenden Code je nachdem ob hinter der Eigenschaft direkt die Feldvariable steht oder ein Getter) ergibt sich die zuvor erwähnte halbherzige Kapselung. Die aus OOP Sicht eine nonbreaking change darstellende Änderung von direktem Feldzugriff auf Setter bedeutet in Delphi tatsächlich technisch (in den Binaries) einen breaking change, da jede Stelle, die in einem solchen Fall lesend auf die Eigenschaft zugreift, neu kompiliert werden muss. Das ist übrigens ebenfalls so, wenn ich den Getter plötzlich als virtual markiere - auch hier erzeugt das einen breaking change für die aufrufende Stelle.

Rollo62 25. Jun 2018 20:17

AW: Interfaces, Verwenden von Gettern
 
Hallo Stevie,

guter Hinweis, danksehr.

Hallo Uwe,
Zitat:

kann ja sogar auch beabsichtigt sein, wenn beim Zugriff über das Interface etwas anderes passieren soll,
Das fände ich aber sehr bedenklich, und Anti-WYSIWYG :stupid:

Dann werde ich da wohl nach wie vor bevorzugt dizipliniert über Getter/Setter drauf zugreifen.

Rollo

Uwe Raabe 25. Jun 2018 21:23

AW: Interfaces, Verwenden von Gettern
 
Zitat:

Zitat von Rollo62 (Beitrag 1405788)
Das fände ich aber sehr bedenklich, und Anti-WYSIWYG

Der Getter ist ja nur die Implementierung des Interfaces und hat ja nicht zwingend etwas mit dem Property zu tun. Betrachte es doch mal wie eine Method Resolution Clause, bei der die Implementierung einer Interface-Methode auf eine andersnamige Methode der Klasse umgeleitet wird, weil es vielleicht schon eine andere Methode mit dem Interface-Namen gibt, die aber ebenso nichts damit zu tun hat.

Du verbindest die Funktion GetBrush ja nur deswegen mit dem Property Brush, weil es die übliche Namensgebung ist. Aus Compilersicht ist GetBrush aber nur die Implementierung des Interfaces.

Sollte der Compiler in diesem Fall etwas verbieten oder erzwingen, fände ich das schon eine gewisse Einschränkung.

Rollo62 26. Jun 2018 10:07

AW: Interfaces, Verwenden von Gettern
 
Hallo Uwe,

das ist ja richtig, wenn es korrekt implementiert wrd.

Mir geht es aber in erster Linie darum das ich das bekomme was ich erwarte.
Und so eine Getter könnte z.B. auch ungewollte Seiteneffekte haben, also hättee ich mit/ohne Interface unterschiedliches Verhalten bei so einer "simplen" Property.
Naja, schon die TBrush könnte in verschiedenen Ableitungen daherkommen, davon mal abgesehen.

Ich vermeide gerne solche Seiteneffekte und Redundanzen in dem ich möglichst immer die gleichen Routinen verwende, auch wenn es vielleicht manchmal lästig und überflüssig ist.

Das Umbiegen von Methoden kann natürlich auch einen Zweck haben und etwas ganz anderes zurückliefern, aber in der Regel erwarte ich dann bei solchen Klassen dann auch das ich etwas Anderes bekommen kann.

Ich versuche meistend den Code so zu halten das ich auch in 6 Monaten direkt noch weiss was eine Methode bewirkt, ohne erst tiefer reinschauen zu müssen.
Dabei möglichst sprechende Namen verwenden, auch wenn sie recht lang werden können.
Möglichst geradlinig ohne Seiteneffekte und Fettnäpfchen, das meine ich mit WYSIWYG.
Leider gelingt mir das aber nicht immer :oops:

Wenn ich aber GetBrush, GetSize, o.ä. sehe, bei relativ simplen Klassen,
dann erwarte ich eigentlich das es keine zwei Wege gibt ohne besonderen Nutzen.

Rollo

Uwe Raabe 26. Jun 2018 10:14

AW: Interfaces, Verwenden von Gettern
 
Zitat:

Zitat von Rollo62 (Beitrag 1405835)
Ich vermeide gerne solche Seiteneffekte und Redundanzen in dem ich möglichst immer die gleichen Routinen verwende, auch wenn es vielleicht manchmal lästig und überflüssig ist.

Das kann ich durchaus nachvollziehen und prinzipiell unterstütze und empfehle ich dieses Vorgehen natürlich auch.

Was mich in diesem Fall die Augenbrauen hochziehen ließ, war die Bemerkung:
Zitat:

Ehrlich hätte ich erwartet, dass der Compiler das gar nicht akzeptiert.
Da tendiere ich doch eher zu der Haltung "Der Entwickler muss schon wissen, was er tut", bevor ich mir durch den Compiler irgendwelche Zügel anlegen lasse, nur weil der eine oder andere eben manchmal nicht weiß, was er tut.


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:03 Uhr.
Seite 1 von 2  1 2      

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