Datenstruktur: Kindobjekt als Objekt oder Record
Hallo,
ich habe ein InterfacedObject mit vielen Eigenschaften, wobei die Eigenschaften vermutlich noch weiter anwachsen werden. Um das einigermaßen übersichtlich und wartbar zu halten, wollte ich entsprechend Kindobjekte mit Eigenschaften erstellen. Hierbei stellt sich die Frage ob Objekt oder Record. Objekt:
Delphi-Quellcode:
Hier sind beispielhaft nur die Feldnamen gelistet, properties, getter und setter bitte dazu denken. In dem Beispiel sind das also 60 Eigenschaften.
TMyObj = class(TInterfacedObject, MyInterface)
Field_A0 Field_A1 ... Field_A9 Field_B0 ... Field_B9 ... Field_F9 Eine Möglichkeit wäre für alle A, B, C, D, E, F - Eigenschaften je ein Objekt oder Record als Kindobjekt zu definieren. Als Interfaces:
Delphi-Quellcode:
Um der Dependency Injection gerecht zu werden, würde der constructor also so aussehen:
TMyObj = class(TInterfacedObject, MyInterface)
Field_A: IGrpA; Field_B: IGrpB; Field_C: IGrpC; Field_D: IGrpD; Field_E: IGrpE; Field_F: IGrpF;
Delphi-Quellcode:
Unnötig zu sagen, das grenzt wieder an Unübersichtlichkeit und überschreitet eine vernünftige Anzahl an Parametern.
constructor TMyObj.create(aGrpA: IGrpA; aGrpB: IGrpB; aGrpC: IGrpC; aGrpD: IGrpD; aGrpE: IGrpE; aGrpF: IGrpF);
Statt dessen alle Kindobjekte als Records erstellen scheint fast naheliegender. Der Nachteil ist, dass es eher langlebige Daten sind und so doch einige Daten (es kommen auch einige Instanzen von TMyObj zusammen) auf dem Stack landen ohne dessen Geschwindigkeit zu benötigen. Die Kindobjekte selbst werden keine Interfaces als Eigenschaften haben, womit Records grundsätzlich möglich sind. Auch Vererbung ist hier kein Thema. Ach ja: Das Thema ByValue oder ByRef spiel hier auch eher eine untergeordnete Rolle, da es nicht zu großen Kopiervorgängen kommt. Zumindest nicht von den Kindobjekten, sondern wenn dann von TMyObj. Zu welcher Lösung würdet ihr greifen? Oder nochmal zu einer anderen? Danke schonmal. |
AW: Datenstruktur: Kindobjekt als Objekt oder Record
Zitat:
Delphi-Quellcode:
Jetzt kannst du dir noch aussuchen, ob du deine öffentlichen Properties auf das gesamte Sammel-Record zeigen lässt oder auf die einzelnen Bestandteile davon.
type
TMyObjData = record GrpA: IGrpA; GrpB: IGrpB; GrpC: IGrpC; GrpD: IGrpD; GrpE: IGrpE; GrpF: IGrpF; end; //... constructor TMyObj.Create(const AMyObjData: TMyObjData); begin Self.FMyData := AMyObjData; // Tataa, fertig! Super erweiterbar, man muss die Methodensignatur des Constructors nicht mehr anpacken! end; |
AW: Datenstruktur: Kindobjekt als Objekt oder Record
Zitat:
|
AW: Datenstruktur: Kindobjekt als Objekt oder Record
Hmm. Ich kenn deine Anforderung nicht, aber ich würde eine dynamische Struktur bauen:
TMyObj = class(TInterfacedObject, MyInterface) fEigenschaften: TList<TEigenschaft,TWert>; end; Ob TList oder sonstwas ist da jetzt eagl. |
AW: Datenstruktur: Kindobjekt als Objekt oder Record
Es sind doch nur Daten, sie tun nichts. "Plain Old Data", in Delphi praktisch immer ein Record, z.B.
Delphi-Quellcode:
.
TMySettings
Deinem tatsächlichen Objekt verpasst du nicht fünf Dutzend Properties, sondern du kannst die
Delphi-Quellcode:
lesen, und du kannst sie setzen. Später willst du diese Einstellungen dauerhaft speichern und laden oder übers Netz übertragen, und kümmerst dich um die Serialisierung von
TMySettings
Delphi-Quellcode:
. Wer oder was das benutzt ist unerheblich.
TMySettings
Wenn du wirklich meinst dass sich messbare Performance-Einbußen über das Pass by value ergeben lässt sich das ganze ja notfalls auch noch über einen Referenztyp wrappen, aber die Daten selbst - Da sehe ich nie was man dadurch gewinnt, das in ein TObject oder gar interface-basiertes Objekt zu verpacken, außer noch mehr Tipparbeit und Komplexität. |
AW: Datenstruktur: Kindobjekt als Objekt oder Record
Zitat:
|
AW: Datenstruktur: Kindobjekt als Objekt oder Record
Ich stehe auf dem Schlauch - Inwiefern ist das ein Problem?
|
AW: Datenstruktur: Kindobjekt als Objekt oder Record
Zitat:
|
AW: Datenstruktur: Kindobjekt als Objekt oder Record
Bin auch Schlauchsteher!
Welches technische Problem steht dem im Weg? |
AW: Datenstruktur: Kindobjekt als Objekt oder Record
Grundsätzlich stellt sich ja die Frage:
- Warum soll ich ein Object, InterfacedObject oder Record verwenden? Alles hat Vor- und Nachteile. Ein Record ist schlank aber bei Übergaben werden die Values normalerweise kopiert, was langsam sein kann (wenn man nicht Pointer benutzt). Ein InterfacedObject ist langsam und speicherhungrig. Dafür kann man sie leicht referenzieren, sie "teilen Funktionalitäten" und sie können automatisch freigegeben werden. Ein Object ist nicht ganz so langsam und speicherhungrig, kann leicht referenziert werden, unterstützt Vererbung, muss aber freigegeben werden. Für Eigenschaften Deiner Klasse stellt sich die gleiche Frage. Interface-Funktionalitäten brauchst Du dafür offenbar nicht - also kannst Du Dir den Aufwand sparen. Bleiben Records und Klassen. Wenn Du diese ständig weitergeben musst, würden sich wohl Klassen anbieten, ansonsten Records. |
AW: Datenstruktur: Kindobjekt als Objekt oder Record
Zitat:
Hatte das mehrfach gelesen, aber immer falsch verstanden. Records können natürlich keine Interfaces implementieren im Sinne von
Delphi-Quellcode:
Aber sehr wohl interfaces als Felder oder properties haben.
MyRec = Record(IMyInterface)
OK...also nochmal weniger das gegen Records spricht. Aber wie seht ihr das Argument den Stack nicht unnötig mit langlebigen Daten zu befüllen? (Die noch dazu keinen Geschwindigkeitsvorteil benötigen weil selten kopiert) |
AW: Datenstruktur: Kindobjekt als Objekt oder Record
Auf einem PC (im Gegensatz zu einem kleinen Mikrocontroller) muss man echt schon einiges anstellen um den Stack voll zu bekommen. Standardmäßig ist die Stack-Größe (pro Thread) in Delphi bei 1 Megabyte (lässt sich einstellen).
Ich bin kein Compiler/Assemblercode-Experte, aber ich würde dem Compiler durchaus zutrauen dass er die Register bzw. den Memory für den Stack wiederverwendet und bei z.B. 5 dicken Records nicht fünf mal allokiert. Und: Wenn man die Daten als
Delphi-Quellcode:
oder
const
Delphi-Quellcode:
übergibt, dann optimiert der Compiler das dorthin gehend, dass die Daten nur per Zeiger übergeben werden.
[Ref]
|
AW: Datenstruktur: Kindobjekt als Objekt oder Record
Zitat:
Delphi-Quellcode:
Habe ich schon erwähnt, dass mORMot diese 1M Records JSON und XML Serialisierung in 1 Sekunde schafft.
uses
mormot.core.base, mormot.core.data, mormot.core.text, mormot.core.json, mormot.core.unicode, mormot.core.variants, mormot.core.os, mormot.core.perf; procedure SpeedTestRecords; type TSubItem = record id: Integer; value: RawUtf8; end; TDataItem = record id: Integer; value: RawUtf8; subItem: TSubItem; end; TDataItems = array of TDataItem; var json, xml: RawByteString; timer: TPrecisionTimer; items: TDataItems; begin SetLength(items, 1000000); for var i: Integer := Low(items) to High(items) do begin items[i].id := i; items[i].value := StringToUtf8('value' + i.ToString); items[i].subItem.id := i; items[i].subItem.value := StringToUtf8('subItem_value' + i.ToString); end; timer.Start; json := DynArraySaveJson(items, TypeInfo(TDataItems)); timer.Pause; FileFromString(json, '_testData.json'); timer.Resume; xml := JsonToXML(json); timer.Pause; FileFromString(xml, '_testData.xml'); WriteLn(Format('Total time: %s', [timer.Stop])); end; Bis bald... Thomas |
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:04 Uhr. |
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