![]() |
Einfache Datentypen schnell zusammenbauen?
Gedenken wir der Zeiten als ein Mann noch ein Mann war. Wollte man Adressen speichern hat wohl ein einfacher Record gereicht:
Delphi-Quellcode:
15 Sekunden Tippen und ich bin einsatzbereit.
TAdresse = record
vorname, nachname: String; straße: String; hausNr: Integer; end; Mache ich es wie Papa sagt, dann natürlich Interface-referenziert. Das ganze Drumherum mit oder ohne Factory, Service-Locator und allem sei mal weggelassen.
Delphi-Quellcode:
Ich will jetzt nicht auf den vielleicht drei Minuten Mehraufwand für das Tippen herumreiten. Aber geht das nicht etwas... komfortabler? Ein sonderlich praxisnahes Beispiel ist das nicht, ja. Aber ich glaube ihr wisst was ich meine.
IAdresse = interface
['{1CA3FB79-CBC2-439E-8333-8F2A8F4CA179}'] function getVorname(): String; procedure setVorname(const vorname: String); function getNachname(): String; procedure setNachname(const nachname: String); function getStraße(): String; procedure setStraße(const straße: String); function getHausNr(): Integer; procedure setHausNr(const hausNr: Integer); end; TMyAdresse = class(TInterfacedObject, IAdresse) public constructor Create(copyOf: IAdresse = nil); // IAdresse function getVorname(): String; procedure setVorname(const vorname: String); function getNachname(): String; procedure setNachname(const nachname: String); function getStraße(): String; procedure setStraße(const straße: String); function getHausNr(): Integer; procedure setHausNr(const hausNr: Integer); end; Ist vielleicht mal jemand über eine Quelltext-Vorlage gestolpert? Irgendwas? |
AW: Einfache Datentypen schnell zusammenbauen?
Kommt halt drauf an, ob man das ganze (Java-„Enterprise“-)Gedöhns wirklich braucht, vor allem der Sinn des Interfaces erscheint mir hier fraglich.
Du kannst dir unter Delphi aber, um Tipparbeit zu sparen, Templates (nicht zu verwechseln mit Generics) definieren (das funktioniert dann genau wie die Autovervollständigung von Schleifen etc). Unter Delphi 2006 ging das bei Bearbeiten → Templates, weiß nicht, ob sich das inzwischen geändert hat. Ich hatte mir damals (bevor es Generics gab) z.B. mal ein solches Template für eine typensichere TObjectList geschrieben:
XML-Code:
Aufrufen kann man ein solches Template dann, indem man im Editor Strg+Leerzeichen drückt und den Templatenamen (oder zumindest den Anfangsbuchstaben eingibt).
<?xml version="1.0" encoding="utf-8" ?>
<codetemplate xmlns="http://schemas.borland.com/Delphi/2005/codetemplates" version="1.0.0"> <template name="objlist" invoke="manual"> <point name="TMyObjectList"> <text> TMyObjectList </text> <hint> Klassenname der Liste </hint> </point> <point name="TMyObject"> <text> TMyObject </text> <hint> Klassenname der Listeneinträge </hint> </point> <description> Typensichere Objektliste </description> <code language="Delphi" context="typedecl" delimiter="|"> <![CDATA[ |*||TMyObjectList| = class(TObjectList) |*|protected |*||*|function GetItem(Index: Integer): |TMyObject|; |*||*|procedure SetItem(Index: Integer; AObject: |TMyObject|); |*|public |*||*|function Add(AObject: |TMyObject|): Integer; |*||*|function Extract(Item: |TMyObject|): |TMyObject|; |*||*|function Remove(AObject: |TMyObject|): Integer; |*||*|function IndexOf(AObject: |TMyObject|): Integer; |*||*|procedure Insert(Index: Integer; AObject: |TMyObject|); |*||*|function First: |TMyObject|; |*||*|function Last: |TMyObject|; |*||*|property Items[Index: Integer]: |TMyObject| read GetItem write SetItem; default; |*|end; { |TMyObjectList| } function |TMyObjectList|.Add(AObject: |TMyObject|): Integer; begin |*|Result := inherited Add(AObject); end; function |TMyObjectList|.Extract(Item: |TMyObject|): |TMyObject|; begin |*|Result := |TMyObject|(inherited Extract(Item)); end; function |TMyObjectList|.First: |TMyObject|; begin |*|Result := |TMyObject|(inherited First); end; function |TMyObjectList|.GetItem(Index: Integer): |TMyObject|; begin |*|Result := |TMyObject|(inherited GetItem(Index)); end; function |TMyObjectList|.IndexOf(AObject: |TMyObject|): Integer; begin |*|Result := inherited IndexOf(AObject); end; procedure |TMyObjectList|.Insert(Index: Integer; AObject: |TMyObject|); begin |*|inherited Insert(Index, AObject); end; function |TMyObjectList|.Last: |TMyObject|; begin |*|Result := |TMyObject|(inherited Last); end; function |TMyObjectList|.Remove(AObject: |TMyObject|): Integer; begin |*|Result := inherited Remove(AObject); end; procedure |TMyObjectList|.SetItem(Index: Integer; AObject: |TMyObject|); begin |*|inherited SetItem(Index, AObject); end; ]]> </code> </template> </codetemplate> Von solches Fällen abgesehen verfolge ich aber eher die Philosophie, möglichst jedes einzelne Zeichen von Hand einzutippen, gerade weil man sich so drei mal überlegt, ob der Code wirklich so lang sein muss, oder ob es nicht auch einfacher und kürzer geht. |
AW: Einfache Datentypen schnell zusammenbauen?
Wozu benötigst Du für ein DTO ein Interface? Ein reines Datenobjekt ist doch genauso dumm wie ein Interface, also: Weg damit.
Es bleibt also, ein 'Property ' vor jedes Feld zu schreiben und dann mit der Codevervollständigung den Rest erledigen zu lassen. Da es hier eh keine Logik gibt, reicht es doch, die Daten in privaten Feldern abzulegen. Einen Setter, der eventuell den Status des Objektes überarbeitet (Modified, Unmodified) kann man noch nachpflegen. Ansonsten gibt es -zumindest bei VS- Refactoring-Tools, um z.B. aus einer Klasse das Interface zu extrahieren und -wie schon erwähnt- Templates, um das immer gleiche Tippen von Pattern zu vereinfachen, z.B.:
Delphi-Quellcode:
Aber wenn dein Beispiel nur ein Beispiel war, dann.. dann sind Refactoring-Tools dein Freund. Da gibt es für Delphi einige Wenige, die sich lohnen, soweit ich das mitbekommen habe.
Procedure SetFoobar (Const Value : String);
Begin if Foobar = Value then exit; fFoobar := Value; RaisePropertyChanged ('Foobar'); End; |
AW: Einfache Datentypen schnell zusammenbauen?
Joar, ich hatte mir war auch schonmal gewünscht, daß man sich von delphi automatisch Interfaces erstellen lassen kann.
Die sollte der Compiler z.B. aus Public-Sachen der entsprechend markierten Objekt-Definition generieren. Ansonsten könnte man sich natürlich auch verschiedene Helferlein erstellen, welche (ähnlich der Klassenvervollständigung) die Definitionen synchronisieren. |
AW: Einfache Datentypen schnell zusammenbauen?
Na, ganz so synchronisierend geht das dann in VS doch nicht. Mit Resharper deklarier ich im Interface eine neue Property und wähle dann 'Implement member in derived classes'.
Aber 'extract interface' gibt es doch in Delphi.... :-) |
AW: Einfache Datentypen schnell zusammenbauen?
Wer die Features der IDE nicht nutzt, ist selber Schuld.
Du fängst dort an:
Delphi-Quellcode:
danach tippst du Folgendes
type
|
Code:
und dann wieder hoch zur Deklaration (Strg+Shift+Hoch) und ab in den privaten Teil
classc[strg+leer]Adresse[enter]
Code:
hoch
propgs[strg+leer]vorname[tab]string[enter]
Code:
hoch
propgs[strg+leer]nachname[tab]string[enter]
Code:
hoch
propgs[strg+leer]straße[tab]string[enter]
Code:
fertig
propgs[strg+leer]hausNr[tab]Integer[enter]
(für String und Integer kann man natürlich auch wieder die Codevervollständigung verwenden, wenn man die nicht ausschreiben möchte) Ich hab mir dafür allerdings das fehlende Property-Template "progs" für
Delphi-Quellcode:
selber gebastelt.
propety {Name}: {Type} read F{Name} write Set{Name}
Oder
Delphi-Quellcode:
Und dann nur noch die Klassenvervollständigung (Strg+Shift+C).
type
TAdresse = class private public constructor Create; override; destructor Destroy; override; property Vorname: string read FVorname write SetVorname; property Nachname: string read FNachname write SetNachname; property Straße: string read FStraße write SetStraße; property HausNr: string read FHausNr write SetHausNr; end; |
AW: Einfache Datentypen schnell zusammenbauen?
Der Konstruktor von TObject ist weder virtuell noch dynamisch, kann also nicht überschrieben werden (d.h. "override" wech) :tongue:
|
AW: Einfache Datentypen schnell zusammenbauen?
ModelMaker Code Explorer wird in diesem Forum gelegentlich (lobend) erwähnt, es enthält Refaktorings, darunter laut
![]() Ich habe das Progamm / die Demo jedoch noch nicht selber getestet. Je nach Umfang der Klassen ist die Zeitersparnis nicht unerheblich, selbst wenn man das Refactoring nur gelegentlich benutzt. (Eigentlich verwende ich nur eines der Original Delphi Refactorings, dieses aber sehr oft - und habe es mir auf F2 gelegt: Rename) |
AW: Einfache Datentypen schnell zusammenbauen?
Zitat:
|
AW: Einfache Datentypen schnell zusammenbauen?
Zitat:
Ist wohl nach dem Motto "besser zu viel, als zu wenig", denn die Override hatte Delphi generiert. :angel2: |
AW: Einfache Datentypen schnell zusammenbauen?
Vielen Dank für die Antworten!
Interface extrahieren ist genau was ich wollte- Das hatte ich mir mittlerweile abgewöhnt da die Refactoring-Funktionen meistens eh nicht funktionieren. Auf die offensichtlichsten Dinge kommt man nie von selbst :spin2: |
AW: Einfache Datentypen schnell zusammenbauen?
|
AW: Einfache Datentypen schnell zusammenbauen?
Man kann das nicht side-by-side machen. Leider fehlt in Delphi die Möglichkeit, im Interface eine Methode hinzuzufügen und diese dann in allen abgeleiteten Klassen automatisch zu deklarieren und zu implementieren.
In Visual Studio erweitere ich mein Interface und lasse dann per Refactoring die neue Methode/Property einfach in alles Klassen, die das Teil implementieren, hinzufügen. Allerdings habe ich Resharper, es wäre also denkbar, das das damit geht. Und vermutlich sind die hier schon vorgestellten Refactoring-Tools für Delphi nicht ganz so schrottig, wie das eingebaute Refactoring von Delphi. Wenn ich mir die Modelmaker-Features anschauen, ist das aber eher ein Productivity-Tool, d.h. die normalen Aufgaben werden einem abgenommen und halbautomatisiert (Add Property, Add Field etc.). Sehr praktisch, aber eben kein Refactoring. |
AW: Einfache Datentypen schnell zusammenbauen?
Na ja, zumindestens die Codevervollständigung bietet dir in der Klasse die Methodennamen der Interfaces, so daß man eine Methode auch ohne Refactoring mit wenigen Klicks hinzugefügt hat.
|
AW: Einfache Datentypen schnell zusammenbauen?
Zitat:
Seit ARC, bin ich ein Fan von Interfaced Objects... Denn seit ich für Android & iOS Programmiere, vergesse ich auf Windows Seite notorisch das Free... Auch für die Wiederverwendbarkeit des Codes... Stichwort "Dependency Injection" ist es sinnvoll. Grüsse Mavarik |
AW: Einfache Datentypen schnell zusammenbauen?
Zitat:
Delphi-Quellcode:
Und so weiter... lief mit Delphi 5 wie mit XE.
{$IFNDEF COMPILER_14_UP}
TTypedObjectListItem = TPosScreenElement; {$define NoNewTypeSection} {$include 'TypedObjectListTemplate.inc'} TPosScreenElementList = class(TTypedObjectListTemplate) {$ELSE} TPosScreenElementList = class(TObjectList<TPosScreenElement>) {$ENDIF} Da die Deklarationen ansonsten bei der generischen Variante gleich waren, lief der Quelltext mit Template und echten Generics parallel. |
AW: Einfache Datentypen schnell zusammenbauen?
So richtig lesbar/übersichtlich ist das ja nicht gerade...
|
AW: Einfache Datentypen schnell zusammenbauen?
Immer noch besser als die ganze Klasse jedesmal neu zu schreiben. Und ohne die Unterstützung der echten Generics brauchst du ja auch den größten Teil nicht. Ohne reicht ja das:
Delphi-Quellcode:
Insbesondere aber die einfache Unterstützung von echten Generics und alten Delphis mit nur wenigen Zeilen fand ich aber sehr interessant, da ich auf Generics nicht verzichten wollte, aber auch möglichst wenig redundanten bzw. extra für alte Versionen geschriebenen Code wollte.
TTypedObjectListItem = TPosScreenElement;
{$include 'TypedObjectListTemplate.inc'} TPosScreenElementList = class(TTypedObjectListTemplate) // und nach dem Implementation noch ein Include |
AW: Einfache Datentypen schnell zusammenbauen?
Den Trick kann man allerdings nur einmal pro Unit verwenden.
|
AW: Einfache Datentypen schnell zusammenbauen?
Nein, ich hatte mehrere ifdefs drin, so dass bis zu drei gingen. Aber sauberer ist ohnehin eine Definition pro Unit.
|
AW: Einfache Datentypen schnell zusammenbauen?
Zitat:
|
AW: Einfache Datentypen schnell zusammenbauen?
Liste der Anhänge anzeigen (Anzahl: 1)
Im Anhang liegt das ganze Template. Beispiel:
Delphi-Quellcode:
TTypedObjectListItem = TLayoutBlockInfo;
{$include TypedObjectListTemplate.inc} TLayoutBlockInfoList = class(TTypedObjectListTemplate) ... TTypedObjectListItem1 = TLayoutExpressionInfo; {$define ObjectList1} {$include TypedObjectListTemplate.inc} {$undef ObjectList1} TLayoutExpressionInfoList = class(TTypedObjectListTemplate1) ... implementation {$define ImplementationSection} {$include TypedObjectListTemplate.inc} {$define ObjectList1} {$include TypedObjectListTemplate.inc} |
Alle Zeitangaben in WEZ +1. Es ist jetzt 04:01 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz