Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Spring Collections erweitern (https://www.delphipraxis.net/179600-spring-collections-erweitern.html)

Rainer Wolff 19. Mär 2014 08:08

Spring Collections erweitern
 
Hallo,

ich versuche grade, meine Anwendung mit dem Spring-Framework und Spring Collections zu ergänzen.

Ich habe eine Klasse

Code:
TMyItem = class
  FLaenge: Double;
published
  property Laenge: Double read FLaenge write FLaenge;
end;
Diese möchte ich in eine TQueue<TMyItem> stecken. Dazu habe ich

Code:
TMyQueue = class(TQueue<TMyItem>)
public
  function Gesamtlaenge: Double; // iteriert über die Items und summiert auf
end;
...
MyQueue = TMyQueue.Create;
MyQueue.Enqueue(TMyItem.Create);
Gesamt:=MyQueue.Gesamtlaenge;
So weit so gut. Allerdings erhalte ich jetzt ein Speicherleck, da die einzelnen Items nicht automatisch freigegeben werden. Müsste ich also immer von Hand machen, will ich aber nicht.

Im Framework kann man ja auch über
Code:
TCollections.CreateQueue<TMyItem>(True);
eine Queue erstellen, die die enthaltenen Items automatisch freigibt. Das funktioniert ja auch. TCollections erzeugt mir allerdings nur eine TQueue, keine TMyQueue, die dann z.b. die Funktion Gesamtlaenge enthält.

Wie würdet ihr das am besten lösen? Doch von Hand im Destructor freigeben? TCollections vererben und um CreateMyQueue ergänzen? Class Helper Gesamtlaenge für die Klasse TQueue?

Scheint mir alles nicht so sauber. Aber da ich mich erst langsam herantaste, sehe ich noch keine gute Lösung.

Gruß Rainer

Der schöne Günther 19. Mär 2014 08:19

AW: Spring Collections erweitern
 
Nur um sich die (für Delphi normale) Freigabe eines aggregierten Objekts im Destruktor (oder woanders) zu sparen steigt man wahrscheinlich nicht auf ein komplett neues Collection-Framework um.

Um ehrlich zu sein, war es bei mir aber ähnlich (Spring Collections sind toll).


Von einem Class Helper hast du nichts- Die gehen ja nur für Klassen, Records und einfache Typen (Integer, String, Enums, ...). Interfaces bleiben außen vor.

Ich persönlich würde meinen, dass sich es nur für die (ziemlich triviale) Eigenschaft "Summe aller Items bzgl. einer bestimmten Eigenschaft" auch nicht lohnt: In diesem speziellen Fall würde ich (ja, jedes mal) hingehen, über alle Items drüberrutschen und aufsummieren:

Delphi-Quellcode:
implementation uses Spring.Collections;

type TMyItem = class
   public var länge: Double;
end;

{$R *.dfm}

procedure TForm25.FormCreate(Sender: TObject);
var
   myQueue: IQueue<TMyItem>;
   gesamtlänge: Double;
begin

   myQueue := TCollections.CreateQueue<TMyItem>();

   // [Queue mit Inhalt füllen]

   gesamtlänge := 0;
   myQueue.ForEach(
      procedure(const item: TMyItem)
      begin
         gesamtlänge := gesamtlänge + item.länge;
      end
   );

   ShowMessage( gesamtlänge.ToString() );
end;

Ansonsten habe ich ehrlich gesagt auch nie wirklich Scheu davor, einen neuen Typen für meine ganz speziellen Zwecke zu erstellen. Also

Delphi-Quellcode:
type
   IMyQueue = interface(IQueue<TMyItem>)
      function getGesamtlänge(): Double;
   end;

   TMyQueue = class( Spring.Collections.Queues.TQueue<TMyItem>, IMyQueue)
      public function getGesamtlänge(): Double;
   end;
Dann sind deine Container nicht mehr vom Typ
Delphi-Quellcode:
IQueue<TMyItem>
sondern
Delphi-Quellcode:
IMyQueue

Rainer Wolff 19. Mär 2014 09:08

AW: Spring Collections erweitern
 
Von Hand jedesmal drüberrutschen mag ich nicht, das macht den Quelltext ja nicht grad übersichtlicher, wenn die Gesamtlänge ein paar mal gebraucht wird.

Und beim normalen Ableiten krieg ich ja wieder keinen Container, der die Objekte selbst aufräumt.

Der schöne Günther 19. Mär 2014 09:22

AW: Spring Collections erweitern
 
Wenn du
Delphi-Quellcode:
TMyItem
noch auf
Delphi-Quellcode:
IMyItem
umstellst hast du das Problem nicht ;-)

Ansonsten müsste man sich wieder eine eigene Fabrikmethode "CreateMyQueue" bauen- Die Spring-Queue geht nur bei
Delphi-Quellcode:
CreateQueue<T: class>(ownsObjects: Boolean): IQueue<T>;
auf eine TObjectQueue, ansonsten immer auf eine normale TQueue.

QuickAndDirty 19. Mär 2014 09:22

AW: Spring Collections erweitern
 
Ist das das Spring das man aus java kennt? Also Aspekt orientierte Programmierung?

Sir Rufo 19. Mär 2014 09:31

AW: Spring Collections erweitern
 
Die einfachste Lösung wäre ja eine Funktion, die so eine Queue als Parameter nimmt und dann die Gesamtlänge zurückgibt.

Der schöne Günther 19. Mär 2014 09:41

AW: Spring Collections erweitern
 
Zitat:

Zitat von QuickAndDirty (Beitrag 1252485)
Ist das das Spring das man aus java kennt? Also Aspekt orientierte Programmierung?

AOP ist in "Spring4D" nicht drin, der Fokus steht wohl eher bei den Collections und IoC.
AOP findest du (glaube ich) bei DSharp.

Für beides ist Stevie so ziemlich der Mann der Stunde :love:


PS:
Müsste so gehen:

Delphi-Quellcode:
interface type
   TMyCollections = class(Spring.Collections.TCollections)
      public class function CreateMyQueue(ownsObjects: Boolean): IMyQueue;
   end;
   
implementation uses Spring.Collections.Queues, System.Generics.Collections;

class function TMyCollections.CreateMyQueue(ownsObjects: Boolean): IMyQueue;
type
   TOwningQueue = System.Generics.Collections.TObjectQueue<TMyItem>;
var
   objQueue: TOwningQueue;
   ownership: TOwnershipType;
begin
   objQueue := TOwningQueue.Create(ownsObjects);

   if ownsObjects then
      ownership := TOwnershipType.otOwned
   else
      ownership := TOwnershipType.otReference;

   Result := TMyQueue.Create(objQueue, ownership);
end;

Stevie 10. Apr 2014 20:40

AW: Spring Collections erweitern
 
Erstmal sorry, dass ich den Thread erst jetzt sehe - ich wünschte, es gäb hier Notifications, die man sich für bestimmte Keywords einrichten könnte. :)

Zu deiner Frage:
TQueue<T> in Spring4D ist "nur" ein Wrapper um die TQueue<T> aus Generics.Collections, um ihr das IQueue<T> Interface zu verpassen. Das verleiht ihr aber auch die Flexibilität bei Bedarf beide Klassen anpassen zu können.

Musst du aber in deinem Fall meiner Meinung nach nicht. Da wir leider in Delphi keine interface helper haben (das wär schön, dann könnte man einfach die Sum Methode aus dem IEnumerable<T> helper nutzen und bumm, fertig).

Egal, du benötigst ja hier eine Summe für die Menge einer konkreten Klasse (TMyItem). Das macht es einfach, da du so keine Selector Delegate brauchst, die dir den zu summierenden Wert (in deinem Fall die Laenge) liefert, was du bei einem IEnumerable<T>.Sum bräuchtest.

Ich würde also folgende simple Lösung vorschlagen, die überhaupt keine Modifikation bestehender Klassen notwendig macht.

Delphi-Quellcode:
function GesamtLaenge(const source: IEnumerable<TMyItem>): Double;
var
  item: TMyItem;
begin
  Result := 0;
  for item in source do
    Result := Result + item.Laenge;
end;
Im Grunde ist das auch genau das, was eine extension Method für IEnumerable<TMyItem> machen würde, nur dass man die Dank (in Delphi nicht vorhandenem) syntactic sugar anders aufrufen kann.


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:26 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