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/)
-   -   Delphi Spring-DI / DelegatedConstructor / Factory für Dummies (https://www.delphipraxis.net/166192-spring-di-delegatedconstructor-factory-fuer-dummies.html)

stahli 2. Feb 2012 11:45

Spring-DI / DelegatedConstructor / Factory für Dummies
 
Ich habe keine Erfahrung mit Interfaces, könnte mir aber inzwischen vorstellen, im nächsten Projekt mit solchen zu arbeiten.

Der Mehraufwand beim definieren der genutzen Klassen (durch zusätzliche Deklaration von Interfaces) und beim Erzeugen der Objekte (durch Zuweisung des Objektes an eine Interfacevariable) lässt sich durch eine bessere Strukturierung des Projektes rechtfertigen.

Wenn man dann die Objekte noch an einer zetralen Stelle erzeugen lässt und dann nur noch mit deren Schnittstellen arbeitet, hört sich das schon interessant an.

In dem Sinne habe ich verschiedenes nachgelesen, bekomme aber (mal wieder) nicht alles unter einen Hut.

Insbesondere konnte ich noch nicht klar verinnerlichen, wozu dieses Spring-Framework nun eigentlich gut ist.
Dann erschließt sich mir nicht der Sinn eines DelegatedConstructor (ich kann doch auch später einem Objekt ein anderes als Property zuweisen).
Und wie wird eine Factory i.d.R. eingesetzt?

Zwar habe ich von allem eine ungefähre Ahnung bekommen, aber der Geistesblitz blieb noch aus.:roll:

Wollt Ihr Euch mal hier zu dem Themenbereich austoben?

schlecki 2. Feb 2012 12:37

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Spring ist nützlich, um deine Objekte zu verwalten. Du kannst hier in der Konfiguration schon angeben, dass ein Interface nur als Singleton genutzt werden kann. Dann wird jede Anforderung an dieses Objekt immer die gleiche Instanz zurückliefern. Es gibt dann noch verschiedene andere Arten z.b. SingletonPerThread (o.ä.)...

Weiterhin musst du nur die Interfaces veröffentlichen, die implementierenden Klassen können komplett im implementation-Teil "versteckt" werden.

intf.pas:
Delphi-Quellcode:
interface

type
  IDatabase = interface(IInterface)
  // GUID
  end;

  IQuery = interface(IInterface)
  // GUID
  end;

implementation

end.
dbimpl.pas:
Delphi-Quellcode:
interface

implementation

uses
  Spring.Container,
  intf;

type
  TMyDatabase = class(TInterfacedObject, IDatabase)
  //
  end;

initialization
  GlobalContainer.RegisterComponent<TMyDatabase>.Implements<IDatabase>.AsSingletonPerThread;
qryImpl.pas:
Delphi-Quellcode:
interface

implementation

uses
  Spring.Container,
  intf;

type
  TMyQuery = class(TInterfacedObject, IQuery)
  //...
  public
    constructor Create(const database: IDatabase); retintroduce;
  end;

initialization
  GlobalContainer.RegisterComponent<TMyQuery>.Implements<IQuery>;

Dann sollte man einmalig:
Delphi-Quellcode:
GlobalContainer.Build
aufrufen. Dadurch werden alle "Regeln" scharf gestellt. Fortan kannst du mit

Delphi-Quellcode:
var
  qry: IQuery;
begin
  qry := GlobalContainer.Resolve<IQuery>;
  // mit qry arbeiten
end;
ein IQuery-Object abrufen und damit arbeiten. Spring kümmert sich automatisch um Dependencies und erzeugt nötigenfalls die Database und reicht diese auch im Konstruktor an die Query weiter.

Gruß
schlecki

neo4a 2. Feb 2012 13:42

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von stahli (Beitrag 1148865)
Dann erschließt sich mir nicht der Sinn eines DelegatedConstructor (ich kann doch auch später einem Objekt ein anderes als Property zuweisen).

Ich beziehe mich einmal auf obiges Beispiel.

Spring ruft beim (internen) Instantiieren von TMyDatabase den Konstruktor ohne Parameter auf. Wenn das nicht geht, muss man bei
Delphi-Quellcode:
GlobalContainer.RegisterComponent<TMyDatabase>.Implements<IDatabase>.AsSingletonPerThread
noch Spring mitteilen, welcher Konstruktor verwendet werden soll. Hier kommt der DelegatedConstructor in's Spiel:
Delphi-Quellcode:
GlobalContainer.RegisterComponent<TMyDatabase>.Implements<IDatabase>.AsSingletonPerThread.DelegateTo(
    function: TMyDatabase
    begin
      Result := TMyDatabase.Create(nil);
    end
  )
Ansonsten ist das Spring-Framework mehr als nur ein DI-Container. Der ist aber der wichtigste Teil. Du weißt ja, dass DI (Dependency Injection) dazu führt, praktisch keine Objekte, die komplexer sind als etwa TStringList, mehr in der Klasse selbst zu erzeugen. Stattdessen bekommt die Klasse die notwendigen Instanzen der erforderlichen Klassen von "außen" zugewiesen.
Zitat:

Nicht das Auto prüft vor Abfahrt, ob die Räder montiert sind, sondern bei der Montage und vor der Abfahrt aus der Fabrik wird dem Auto alles notwendige an- und eingebaut.
Auch ohne die Notwendigkeit, sein Programm ohnehin zu flexibilisieren, gibt es immer genau einen Anwendungsfall für ein solches Vorgehen: der Test. Da schiebe ich (von außen) meiner Klasse alle die Szenarien unter (in Form von Mock-Instanzen), für die sie funktionieren soll.

So gesehen führt DI zu testbaren Code führt zu Clean-Code führt in den Programmierer-Himmel. ;)

Stevie 2. Feb 2012 14:14

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Ich kann in diesem Bezug nur auf dieses Dokument von Miško Hevery verweisen. Dort wird anhand von simplen Beispielen (zwar in Java aber sollte kein Problem sein) erklärt, wie man bestimmte Dinge in seinem Code vermeidet (allem voran das Erstellen von neuen Objekten - simple Dinge wie z.B. Listen außen vor) und dadurch einfach zu wartenden und testbaren Code erstellt. Auch die in dem Dokument verlinkten Artikel sind sehr interessante Lektüre.

Auch lohnt es sich, diesen Vortrag von ihm zum gleichen Thema anzuschauen

stahli 8. Feb 2012 20:22

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Ok danke erst mal.

Mit dem Thema Testing tue ich mich etwas schwer. Ich habe mal zwei deutsche Seiten dazu gefunden:
http://sageniuz.wordpress.com/2010/0...ktoren-teil-1/
http://msdn.microsoft.com/de-de/magazine/dd263069.aspx
Ich denke, dass solche Tests nur sehr begrenzten Sinn machen. Jedenfalls sind die Probleme, die mir so unterkommen meist sehr komplexen Umständen geschuldet, die sich nicht mit ein paar Testobjekten reproduzieren lassen.
Mal reagiert die VCL etwas anders als erwartet (was z.B. irgendwelche Nachrichtenbehandlungen betrifft) oder in meinem Framework werden irgendwann Objekte nicht wie erwartet behandelt. Jedenfalls treten die Fehler meist nur durch eine intensive Userbedienung auf. In den Fällen dürfte ein Unittesting nicht helfen.
Das nur mal am Rande.

Interfaces zu nutzen und vielleicht auch Spring merke ich mir aber auf jeden Fall mal vor.
Muss mich aber erst noch ein bissl mehr damit beschäftigen.

In meiner Turniersoftware merke ich jetzt zumindest allmählich, dass pure Objekte noch nicht wirklich das Wahre sind. Diese irgendwo zentral zu erzeugen und dann mit Interfaces weiter zu arbeiten, stelle ich mir (inzwischen) sehr übersichtlich vor. Ich werde das Projekt jetzt erst mal zum Ende bringen und später mal eine Überarbeitung andenken.

s.h.a.r.k 9. Feb 2012 07:32

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von stahli (Beitrag 1149980)
Mal reagiert die VCL etwas anders als erwartet (was z.B. irgendwelche Nachrichtenbehandlungen betrifft) oder in meinem Framework werden irgendwann Objekte nicht wie erwartet behandelt. Jedenfalls treten die Fehler meist nur durch eine intensive Userbedienung auf. In den Fällen dürfte ein Unittesting nicht helfen.

Klingt irgendwie komisch... Egal, wie die Nachrichtenbehandlung abläuft, es müsste immer das selbe Ergebnis folgen, egal, wie intensiv die Userbedienung ist. Selbst, wenn du Threads mit einbaust, muss dein Konzept immer die gleichen Ergebnisse liefern, ebenso muss dein Framework immer gleich mit Objekten umgehen, eben auf abstrakte Art und Weise. Die Besonderheiten sollten imho von den Objekten selbst gehandhabt werden.

stahli 9. Feb 2012 09:09

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Es ging mir um Fehler, die bei der Weiterentwicklung meiner datensensitiven Komponenten und meines Frameworks aufgetreten sind. Entweder haben die VCL-Controls (von denen ich ableite) teilweise nicht wie erwartet funktioniert oder ich habe den Ablauf meines Frameworks an irgendeiner Stelle problematisch verändert.
Diese Probleme hätte wohl kein Unit-Testing entdeckt - denke ich. Und Probleme, die ich mit einem Unit-Testing finden könnte, habe ich eigentlich nicht und wenn, sind sie eigentlich schnell zu bereinigen.

Stevie 9. Feb 2012 09:52

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von stahli (Beitrag 1150038)
Es ging mir um Fehler, die bei der Weiterentwicklung meiner datensensitiven Komponenten und meines Frameworks aufgetreten sind. Entweder haben die VCL-Controls (von denen ich ableite) teilweise nicht wie erwartet funktioniert oder ich habe den Ablauf meines Frameworks an irgendeiner Stelle problematisch verändert.
Diese Probleme hätte wohl kein Unit-Testing entdeckt - denke ich. Und Probleme, die ich mit einem Unit-Testing finden könnte, habe ich eigentlich nicht und wenn, sind sie eigentlich schnell zu bereinigen.

Du arbeitest allein an deinem Sourcecode. Stell dir vor, es gibt ein Team von Entwicklern und es gibt bestimmte Spezifikationen für die unterschiedlichen Module und Klassen. Baut sich nun jeder Entwickler seine Button1 Projekte, um zu testen, ob die Klassen und Methoden das machen, was sie sollen? Ob nun TDD betrieben wird, oder erst drauflos gecodet wird und hinterher der Unittest geschrieben wird, ist dafür erstmal unerheblich. Was, wenn nun Funktionialität hinzukommt, sich Spezifikationen ändern, jemand Dinge refactored oder ein unbedarfter Azubi auf den Code losgelassen wird? Willst du deine komplette zig Millionen LoC schwere Anwendung durchtesten, um herauszufinden, ob alles noch funktioniert?

stahli 9. Feb 2012 10:34

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Ok, in Bezug auf die Teamarbeit ist das gewissermaßen schon nachvollziehbar. Damit habe ich aber (leider oder zum Glück?) keine Erfahrungen.
Die Testfälle zu organisieren ist aber sicher auch nicht trivial und kostet viel Zeit und Arbeit.

Da ich immer im eigenen Saft schmore und mit meinem eiegntlichen Projekt voran kommen will, habe ich leider wenig Zeit mich mit für mich neuen Grundlagen zu befassen. Im nächsten Leben werde ich mal bei Dir Azubi und lerne das gleich richtig. :-)

Uwe Raabe 9. Feb 2012 10:42

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von stahli (Beitrag 1150069)
Da ich immer im eigenen Saft schmore und mit meinem eiegntlichen Projekt voran kommen will, habe ich leider wenig Zeit mit frü mich neuen Grundlagen zu befassen.

Dann geht es dir wie dem Bauern, der keine Zeit hat, einen Zaun zu bauen, weil er die Kühe einfangen muss...

stahli 9. Feb 2012 11:25

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von Uwe Raabe (Beitrag 1150071)
Dann geht es dir wie dem Bauern, der keine Zeit hat, einen Zaun zu bauen, weil er die Kühe einfangen muss...

[OT]Ach das geht schon erst mal. Um die Weide ist ein kleiner Graben und wenn die Melkanlage erst mal auf vollen Touren läuft, dann schaue ich mir an, wie man am besten stabile Zäune baut :-) [/OT]

s.h.a.r.k 9. Feb 2012 12:04

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Du weißt aber nicht, was du eigentlich verpasst, wenn du dich endlich mal um den Zaun kümmern würdest ;)

Jens01 9. Feb 2012 13:20

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Ich glaube, dass eine wichtige Komponente von Dir außer Acht gelassen wird. Es gibt da nämlich noch die Haftung, die Du eigentlich mit den AGBs (Eula usw) bei kommerzieller Software (und bei OSS) ausschaltest. Wenn Du aber Deiner Sorgfaltspflicht nicht nachkommst, könntest Du in eine solche aber wieder geraten( siehe BGB). Und ein Unittesting könnte bei kommerzieller Software ein Richter schon als Sorgfalt auslegen(, meine ich, der zwar kein Rechtsanwalt ist, aber mit den Jungs viel zu tun hatte).
Gruss Jens

neo4a 10. Feb 2012 08:56

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Der (visuelle) Delphi-RAD-Ansatz, der den Einsatz mehrerer/vieler miteinander verknüpfter Komponenten bedeutet, steht einer vernünftigen, automatisierten Teststrategie entgegen.

Erzeuge ich dagegen die Komponenten aber bereits im Code, dann ist der Übergang zu DI-Containern sehr viel einfacher realisierbar. Damit ist auch die Ableitung eigener Komponenten inklusive Test viel leichter umsetzbar.

Angenommen ich habe z.B. 4 Panels, die auf einen Click reagieren sollen. Delphi-RAD: Ich weise jedem Panel sein OnClick-Event zu und implementiere dort den Ablauf. Unterscheidet sich der Ablauf nicht bis auf eine Kennung, so fassen ich die 4 Aufrufe vielleicht zusammen und werte den Sender in einer IF-ELSEIF-Konstruktion aus. Werte ich dagegen sogar das TAG-Property aus, vereinfache ich es noch weiter. So macht das wohl jeder irgendwann.

Was kann nun passieren? Bei einem 5. Panel "vergesse" ich das Onclick oder das Tag oder die Auswertung im OnClick.

Hilfreich kann schon eine solche Konstruktion sein:
Delphi-Quellcode:
constructor TMainForm.Create(AOwner: TComponent);
begin
  SetupPanelClick([pnlA, pnlB, pnlC, pnlD]);
end;

procedure TMainForm.SetupPanelClick(aPanels: array of TPanel);
var
  aPanel : TPanel;
begin
  for aPanel in aPanels do
    aPanel.OnClick := DoOnPanelClick;
end;
Diese Konstruktion sichert die visuellen Einstellungen im IDE-Inspektor noch einmal im Code ab. Der Aufwand ist gering, der Effekt dagegen hoch, insbesondere wenn es um zahlreiche Properties geht. Als Seiteneffekt gibt's damit auch einen Fehler, wenn einmal ein Panel versehentlich gelöscht wird.

Eines aber bleibt: Das Panel kann mir beim Setup nicht helfen, denn woher soll es denn wissen, wofür es da ist? (Mit GUI-Tests kann ich wenigstens nocht überprüfen, ob das Panel so reagiert, wie es soll.)

Erst wenn ich ein eigenes Panel ableite, das die Funktionalität beinhaltet, komme ich dem Testansatz näher: Ich verlagere die Funktionalität z.B. des "Geklickt"- Werdens in das Panel und gebe über ein Event und/oder Property das Ergebnis nach "außen". Das kann ich testen, da ist nichts komplex. (Da habe ich also meinen Zaun für die Kühe.)

Ich kann nun sogar mein Panel nun hinter ein Interface IMyPanel stecken und die Verwaltung einem DI-Container überlassen. So muss ich am "Einsatzort" keine spezielle Unit für TMyPanel einbinden, sondern nur die (zentrale) Interface-Deklarations-Unit. Damit habe ich ein gut entkoppeltes System, das leicht(er) testbar ist und bin auch noch flexibel: ich kann TMyPanel schnell durch TMyBevel ersetzen (wenn das IMyPanel implementiert).

Wer das bis hierhin gelesen hat, wird möglicherweise skeptisch anmerken, dass, wenn ich alles zu Fuß mache, ich ja gar keinen IDE-Designer mehr brauche. Stimmt wohl, letztlich läuft es darauf hinaus. Außerdem leben viele komplexe Komponenten-Sammlungen von automatischen Verknüpfungen, die auf RTTI basieren (leicht zu erkennen an Manager-Komponenten). Insofern:

Der (visuelle) Delphi-RAD-Ansatz, der den Einsatz mehrerer/vieler miteinander verknüpfter Komponenten bedeutet, steht einer vernünftigen, automatisierten Teststrategie entgegen.

Stevie 10. Feb 2012 09:32

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von neo4a (Beitrag 1150264)
Der (visuelle) Delphi-RAD-Ansatz, der den Einsatz mehrerer/vieler miteinander verknüpfter Komponenten bedeutet, steht einer vernünftigen, automatisierten Teststrategie entgegen.

Da muss ich dir ausnahmsweise mal widersprechen. Es kommt darauf an, wie weit ich den RAD-Ansatz gehe. Ich sehe es bei uns in der Software, dass ich manchmal einen Frame aufmache und mich eine graue gähnende Leere anschaut und ich erst im Source rumwühlen muss, um zu sehen, wo welche Komponenten erzeugt und platziert werden. Das ist für mich persönlich der Horror. Wo man dann die Businesslogik implementiert, steht auf einem anderen Blatt. Und dort kann dann sehr wohl DI zum Zuge kommen. Dennoch würde ich niemals meine GUI im Source zusammen bauen.

stahli 10. Feb 2012 10:04

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Hi neo,

danke für den aufführlichen Beitrag. Das klingt an den meisten Stellen auch sehr plausibel und den Weg werde ich weiter andenken.

Allerdings sehe ich das wie Stefan, dass man GUI und BL getrennt betrachten sollte.

Die BL mit DI und Interfaces aufzubauen ist mit Sicherheit eine gute Sache und trägt zur Übersichtleichkeit bei der Projektwartung bei.

Die GUI würde ich aber (fast) immer in der IDE zusammenklicken wollen (außer in dynamischen Bereichen, die Abhängig von BL und Daten aufgebaut werden müssen).
In dem Zusammenhang ist dann natürlich eine gute Datenbindung hilfreich.

Insofern ist Dein Panel-Beispiel nicht ganz passend. Das Panel sollte nur als Userinface dienen, ohne selbst irgendwelche Zustände zu verwalten. Man könnte also z.B. ein Objekt an das Panel binden, dessen Eigenschaft ClickCount erhöht wird, wenn das Panel angeklickt wird. Weiterhin zeigt das Panel in seinem Caption die Eigenschaft ClickCount des gebunden Objektes an (sofern ein Objekt angebunden ist).
Dem Objekt ist es dabei wiederum wurscht, ob es irgendwelche Panels gibt, die gerade an es selbst gebunden sind.

Also sehe ich nicht die Notwendigkeit, GUI-Controls über ein Framework erzeugen zu lassen. In Bezug auf die BL- und Datenschicht begeistert mich das Thema aber immer mehr... :-)

Nochmal zum Testen:
Stell Dir vor, in Deinem Panel-Projekt baust Du einen Timer ein, der nach 1 Stunde feuert und in dem Du versehentlich Panel3 löschst. Da kannst Du doch Unit-Tests durchführen wie Du willst und wirst das Problem nicht aufdecken. Die Panels, egal ob mit Ereignisbehandlungen oder Ableitungen werden "in sich" korrekt funktionieren. Aber im Zusammenspiel des gesamten Projektes treten dann doch Probleme auf, die nach 1 Stunde zum Tragen kommen.
Ich kann nachvollziehen, dass man mit solchen Tests bestimmte versehentliche Änderungen (Seiteneffekte) in einem sehr engen Umfeld abfangen kann, aber vermutlich ist das wichtiger, wenn man im Team arbeitet.
Ich denke, dass zumindest in meinen Projekten der Aufwand zum Nutzen in keinem sinnvollen Verhältnis steht.


Aber auf den Rest freue ich mich schon. :-)


@Stevie
In Deinem letzten Satz stimmt etwas noch nicht... NO GUI? :stupid:

stahli 10. Feb 2012 11:47

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Mal noch eine andere Frage, die aber auch in den Bereich mit hineinspielt:

Im Moment erzeuge ich diverse Objekte, die ineinander verschachtelt sind.
Eine Turnierveranstaltung enthält Turniere, die wieder Spiele enthalten, die wieder Spielparteien und zu spielende Sätze enthalten usw.
Über eine Iteration über Spiel.Owner..Owner..Owner kann ich ermitteln, zu welchem Turnier ein bestimmtes Spiel eigentlich gehört.

Ich verwalte also nicht explizit Spiel.Turnier als Eigenschaft. Über die (in einer Funktion verpackte) Iteration kann ich also für jedes Objekt bei Bedarf ermitteln, ob es in einem bestimmten Turnier enthalten ist bzw. zu einem bestimmten Turnier gehört.

Wenn ich meine Objekte künftig in einer Factory erzeugen lasse und daraufhin nur noch mit Schnittstellen arbeite, fällt diese Möglichkeit ja weg - oder?

Wie sollte man solche Beziehungen und Verschachtelungen am sinnvollsten verwalten?

Stevie 10. Feb 2012 12:35

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Dieses Owner Verketten verletzt ganz klar das Gesetz von Demeter. Dein Beispiel zeigt für mich ein gravierendes Designproblem. Sofern der angesprochene Code innerhalb einer TSpiel Klasse ist und diese implizit eine Abhängigkeit auf ein TTurnier hat, dann solltest du das auch dementsprechendüber eine TTurnier Eigenschaft in deiner TSpiel Klasse implementieren und nicht auf Implementierungsdetails an anderen Stellen (zum Beispiel über das Verketten von Owner) vertrauen. Wenn sich diese verändern, bricht dein Code an einer ganz anderen Stelle auseinander.

Hier auch nochmal der Hinweis: Unterscheide bei DI simple Datenklassen und Klassen, die wirklich Businesslogik übernehmen. Ein DI ist imo nicht dazu da, dir einen kompletten Objectgraph für ein Turnier, inklusive Austragungsorten, Spielen und Spielern aufzubauen (ich gehe hier davon aus, dass die besagten Objekte nur PODOs sind).

exilant 10. Feb 2012 13:18

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Ich bin in der gleichen Situation wie Stahli, arbeite also an allein an einem über die Jahre gewachsenem Projekt. Ich habe mich in letzter Zeit ebenfalls mit den hier besprochenen Teckniken beschäftigt und sie für mich verworfen. Das ganze Kram führt zu imo zu "over engeneering". Zu Spring habe ich eine Session bei der EKON besucht und diverse Literatur durchgeackert. Es ist mir gänzlich verborgen geblieben wobei mich ein solches Framework unterstützen könnte. Unit testing lohnt den Aufwand nicht, und Interfaces benutze ich nur wenn ich gezwungen bin mich mit COM zu beschäftigen. In meiner Software sehe ich keinerlei Mehrwert gegenüber abstrakten Methoden. Demeters Gesetz hat was für sich, als allgemeiner Ratschlag. Aber wer sich ständig dran hält schreibt sich die Finger Wund. Für (fast) nichts. Selbst Heiligtümer wie die GOF Patterns haben sich für mich als nur eingeschränkt nützlich erwiesen. Die eine oder andere Idee dahinter ist OK und lässt sich nutzen. Das war es aber auch schon. Wiederverwendbarkeit ist gut, aber um den alten Spruch zu bemühen: Was nach allen Seiten offen ist, ist vermutlich auch nicht ganz dicht. Offensichtlich schlage ich mich nur mit trivialen Problemen herum. Ich habe mich noch nicht in der Situation befunden, ein Problem nicht mit einer einfachen und klaren dem Anwendungsfall angepassten Objekthierachie lösen zu können. Es werden viele Säue durch viele Dörfer getrieben. Ich denke zu viele.

stahli 10. Feb 2012 13:34

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Die "Objekte" sind von TComponent abgeleitet (damit sie einen Owner haben und ich sie ggf. auch in der IDE einrichten kann) und enthalten Daten und BL.

Will ich in einem Spiel ermitteln, ob es sich in einem Turnier befindet, nutze ich eine lokale Variable und eine externe (in einer gesonderten Unit abgelegten) Funktion.

Delphi-Quellcode:
function OwnerTournament(C: TComponent): TodTournament;
begin
  Result := nil;
  if C is TodTournament then
    Result := (C as TodTournament)
  else if C.Owner <> nil then
    Result := OwnerTournament(C.Owner);
end;
Im Spiel dann etwa:

Delphi-Quellcode:
procedure TodGame.Calc;
var
  MyTournament: TodTournament;
begin
  ...
  MyTournament := OwnerTournament(Self);
  if Assigned(MyTournament) then
    MyTournament.Calc;
  ...
end;
Auf diese Weise kennt ein Spiel zwar nicht unmittelbar sein Turnier, kann dieses aber bei Bedarf ermitteln und dort z.B. die Ermittlung der Platzierungen veranlassen (das sollte ja erfolgen, wenn ein Spiel neue Ergebnisse hat).

Für SOOO schlecht halte ich dieses Konstrukt eigentlich nicht.

Deinen letzten Satz kann ich nicht im Detail nachvollziehen. Sollte man BL-Klassen und Datenklassen getrennt definieren und erzeugen? Wo liegt der Vorteil?

Im Moment kann der User ein neues Projekt anlegen, was einem TodTournamentEvent.Create() entspricht. Einige SubObjekte werden dann automatisch (leer) hinzugefügt, z.B. Sportart und Ort. Diese SubObjekte können dann durch den User über bestimmte Formulare bearbeitet und gefüllt werden. Andere Objekte erzeugt der User bei Bedarf komplett neu (z.B. Vereine und deren Mitglieder).
Jedes Objekt beinhaltet seine eigene BL und kann sich bei Bedarf in seinem Umfeld zurecht finden. Starre Verdrahtungen gibt es aber kaum.

Stevie 10. Feb 2012 14:28

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von stahli (Beitrag 1150317)
Auf diese Weise kennt ein Spiel zwar nicht unmittelbar sein Turnier, kann dieses aber bei Bedarf ermitteln und dort z.B. die Ermittlung der Platzierungen veranlassen (das sollte ja erfolgen, wenn ein Spiel neue Ergebnisse hat).

Für SOOO schlecht halte ich dieses Konstrukt eigentlich nicht.

Ich schon. Was hat ein Spiel mit den Platzierungen zu tun? Ich werf nochmal so einen Begriff in den Raum: Single Responsibility Prinzip. Lösung für das Konkrete Problem: Observer (aka Events)

Zitat:

Zitat von stahli (Beitrag 1150317)
Deinen letzten Satz kann ich nicht im Detail nachvollziehen. Sollte man BL-Klassen und Datenklassen getrennt definieren und erzeugen? Wo liegt der Vorteil?

Klares kommt drauf an. Aber es geschieht oft, dass die Businesslogik in diesen Klassen fehl am Platz sind und man damit zwangsläufig wieder irgendwelche Prinzipien (z.B. LoD oder SRP) verletzt. In deinem geschilderten Fall könnte es aber in der Tat Sinn ergeben, den Weg über einen Container zu gehen.

Um es nochmal zu erwähnen: Beschäftigt euch erst mit DI an sich, verinnerlicht, was man dadurch gewinnt und was man ggf aufgeben muss (in der Regel schlechte Angewohnheiten). Die Benutzung eines DI Containers ist eine Stufe weiter. Wenn man nicht manuell DI betreiben kann (TSomeComponent.Create(OtherComponent) IST dependency injection!), kann man's auch nicht mit nem Container.

Zitat:

Zitat von exilant (Beitrag 1150315)
Ich bin in der gleichen Situation wie Stahli, arbeite also an allein an einem über die Jahre gewachsenem Projekt. Ich habe mich in letzter Zeit ebenfalls mit den hier besprochenen Teckniken beschäftigt und sie für mich verworfen. Das ganze Kram führt zu imo zu "over engeneering". Zu Spring habe ich eine Session bei der EKON besucht und diverse Literatur durchgeackert. Es ist mir gänzlich verborgen geblieben wobei mich ein solches Framework unterstützen könnte. Unit testing lohnt den Aufwand nicht, und Interfaces benutze ich nur wenn ich gezwungen bin mich mit COM zu beschäftigen. In meiner Software sehe ich keinerlei Mehrwert gegenüber abstrakten Methoden. Demeters Gesetz hat was für sich, als allgemeiner Ratschlag. Aber wer sich ständig dran hält schreibt sich die Finger Wund. Für (fast) nichts. Selbst Heiligtümer wie die GOF Patterns haben sich für mich als nur eingeschränkt nützlich erwiesen. Die eine oder andere Idee dahinter ist OK und lässt sich nutzen. Das war es aber auch schon. Wiederverwendbarkeit ist gut, aber um den alten Spruch zu bemühen: Was nach allen Seiten offen ist, ist vermutlich auch nicht ganz dicht. Offensichtlich schlage ich mich nur mit trivialen Problemen herum. Ich habe mich noch nicht in der Situation befunden, ein Problem nicht mit einer einfachen und klaren dem Anwendungsfall angepassten Objekthierachie lösen zu können. Es werden viele Säue durch viele Dörfer getrieben. Ich denke zu viele.

Ich arbeite selber an einem über Jahre gewachsenen Projekt und erlebe täglich die Probleme, die mit Nichtbeachtung diverser Prinzipien einherkommen (stundenlange Suche in weniger bekanntem Source und nachverfolgen bestimmter Programmabläufe durch Bereiche hindurch, wo sie nix zu suchen haben z.B.)

Was man davon hat, wenn bestimmte Schnittstellen nicht flexibel sind, kennt jeder, der schonmal von verschiedenen Herstellern ein Mobiltelefon hatte (hey, jeder hat seinen eigenen Stecker für das Ladekabel...) Und wie gut, dass man man in der Regel nicht beim Kauf einer neuen Glühbirne den Hersteller der Lampe wissen muss, weil die ihre eigenen Fassungen haben, oder? Oder dass der Hersteller seine Lampen nur mit 40 Watt Osram Birnen getestet hat und sie mit den anderen Herstellern kaputt geht. Aber bei Software muss immer alles ineiner verbacken sein und wenn man von Modularität spricht, wird die "over engeneering" Karte ausgespielt.

exilant 12. Feb 2012 13:19

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von Stevie (Beitrag 1150326)
[...] Aber bei Software muss immer alles ineiner verbacken sein und wenn man von Modularität spricht, wird die "over engeneering" Karte ausgespielt.

Niemand hat was gegen ordentliche Programmierung. Aber die Framework- und Patternbesessenheit führt zum "Schweizer Taschenmesser Syndrom". Die Teile sind flexibel bis zum abwinken und können immer mehr Dinge immer schlechter erledigen. Kein Mensch will mit sowas arbeiten. Ein Messer ist ein Messer und ein Schraubendreher ein Schraubendreher. Profis arbeiten nicht mit Schweizer Taschenmessern.

neo4a 12. Feb 2012 14:26

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von Stevie (Beitrag 1150273)
Zitat:

Zitat von neo4a (Beitrag 1150264)
Der (visuelle) Delphi-RAD-Ansatz, der den Einsatz mehrerer/vieler miteinander verknüpfter Komponenten bedeutet, steht einer vernünftigen, automatisierten Teststrategie entgegen.

Da muss ich dir ausnahmsweise mal widersprechen. ... Dennoch würde ich niemals meine GUI im Source zusammen bauen.

Ich habe mich nicht ganz präzise ausgedrückt, sorry. Was ich vor allem ansprechen wollte sind die GUI- und Persistenz- unterstützenden Komponenten, wo man halt dann die ganzen Properties im OI zusammenklickt.

Dass mein Beispiel nicht ganz passt, ist meinem Versuch geschuldet, den "Delphi-Weg" bei der Herangehensweise zu simulieren. Hätte ich vielleicht etwas besser machen können.

neo4a 12. Feb 2012 14:53

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von exilant (Beitrag 1150620)
Zitat:

Zitat von Stevie (Beitrag 1150326)
[...] Aber bei Software muss immer alles ineiner verbacken sein und wenn man von Modularität spricht, wird die "over engeneering" Karte ausgespielt.

Niemand hat was gegen ordentliche Programmierung. Aber die Framework- und Patternbesessenheit führt zum "Schweizer Taschenmesser Syndrom". Die Teile sind flexibel bis zum abwinken und können immer mehr Dinge immer schlechter erledigen. Kein Mensch will mit sowas arbeiten. Ein Messer ist ein Messer und ein Schraubendreher ein Schraubendreher. Profis arbeiten nicht mit Schweizer Taschenmessern.

Dein Beitrag ist aus meiner Sicht leider nur rhetorisch gut, denn: Modularität, Clean-Code und die Anwendung von Design Pattern hat doch nichts mit Besessenheit und "Flexibilität bis zum Abwinken" zu tun. Vielmehr bilden sie einen abgesicherten Regelsatz, der nicht nur, aber vor allem in der Teamarbeit soetwas wie eine STVO für Programmierer darstellt.

Und Deine Schlussfolgerung, dass nur der, wer auf diese Ansätze verzichtet, wahrhaft Ergebnisse für Profis abliefern kann, leuchtet mir nicht ein.

exilant 13. Feb 2012 10:36

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von neo4a (Beitrag 1150641)
Und Deine Schlussfolgerung, dass nur der, wer auf diese Ansätze verzichtet, wahrhaft Ergebnisse für Profis abliefern kann, leuchtet mir nicht ein.

Ich geb's zu. Der letzte Satz war eine rethorische Platzpatrone. Das mit der StVO verstehe ich durchaus. In einem Team wo die rechte nicht weiss was die linke tut sind verbindliche Spielregeln unerlässlich. Ich argumentierte auch ausdrücklich aus meiner Sicht: Einzelkämpfer. Ich wage die gar nicht so kühne Behauptung: Die Anzahl der Delphi Projekte in denen mit Dunit/DSpring gearbeitet wird ist verschwindend gering. Diese Erfahrung habe ich auf der letzten EKON machen dürfen als einer der Speaker in die Runde fragte, wer denn alles ein Unit Testing Framework einsetzt (ich glaube es war Herr Ua). Und er war sehr erstaunt (schockiert?) als sich kein Anwesender meldete. Mag daran liegen dass die Delphi Community durchaus an Überalterung leidet und man alten Hunden nur sehr schlecht neue Tricks beibringen kann. Aber nochmal (nicht Arrogant gemeint): Mein Problem bei der Softwareentwicklung ist nicht die Qualität sondern die Produktivität. Ich denke, das geht den meisten hier so.

"Patterns are unlikely to cover every aspect of an architecture. Any non-trivial design has lots of aspects that no pattern addresses. It’s up to you to fill in the spaces with your own creativity."

neo4a 13. Feb 2012 12:15

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von exilant (Beitrag 1150735)
Mein Problem bei der Softwareentwicklung ist nicht die Qualität sondern die Produktivität.

Etwas weiter vorn gab's schon einmal ein Bild mit "Kuhzäunen". Und egal wie alt einer ist: Wer sich professionell mit IT-Themen beschäftigt, kennt die schnellen Zyklen und die kurzen Halbwertzeiten von IT-Expertenwissen. Ich bin überzeugt, dass es zwischen Qualität und Produktivität bei der Software-Entwicklung einen Zusammenhang gibt.

Einige Impulse kommen ja auch davon, dass viele Leute hier nicht mehr ausschließlich nur in Delphi unterwegs sind. Beispielsweise in XCode kommt man mit dem herkömmlichen Delphi-Ansatz nicht sehr weit.

Daraus mehme ich meine Motivation: Mache es schon in Delphi so, wie es auch in anderen Sprachen anwendbar ist, damit ein Sprach- oder Plattform-Wechsel im Idealfall nur noch eine Syntax-Umstellung ist.

Du kennst vielleicht schon die Erläuterungen auf Sourcemaking.com. Interessanterweise werden hier die Beispiele auch meist noch für Delphi ausgeführt.

Jens01 13. Feb 2012 12:48

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Ich verfolge ja gerade diesen Thread...

Wenn ich das richtig mit diesem Spring verstehe, dann muß man bei den Klassen konsequent Daten und Funktion aufteilen in je eine Extra-Klasse und die Klasse mit den Funktionen kommt dann in diesen GlobalContainer.

Verstehe ich das richtig?

Gruss Jens

neo4a 13. Feb 2012 14:02

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von Jens01 (Beitrag 1150772)
Verstehe ich das richtig?

Hier ein kleines Kochbuch:

Das Prinzip des Spring-DI-Containers ist - mit etwas Phantasie - vergleichbar mit den Abläufen bei der Automontage. Dort ist es ja eher unüblich, beim Montieren (Create) des Autos die Bestandteile (Motor, Blinker etc.) ebenfalls mit herzustellen: sie werden stattdessen aus dem Warenlager (DI-Container) so beigestellt, wie sie in der Produktion beim Create() des Autos benötigt werden.

In Spring meldest Du die Klassen, die Du im Warenlager verwalten willst, im einfachsten Fall so an:
Delphi-Quellcode:
unit uMotor;

interface

uses
  classes;

type
  IMotor = interface
    ['{F23C0AAF-0D7F-4CFF-A4A6-FDEB4EC5FDF0}']
    procedure Brumm;
  end;

implementation

uses
  Spring.Container,
  Spring.Services;

type
  TMotor = class(TInterfacedObject, IMotor)
  private
    procedure Brumm;
  end;

initialization
  GlobalContainer.RegisterComponent<TMotor>.Implements<IMotor>.AsSingleton;
Das passiert analog auch in den Units uBlinker etc.

Ich rufe i.d.R. in der dpr-Datei auf:
Delphi-Quellcode:
GlobalContainer.Build;
Dieser einmalige Aufruf ist erforderlich, damit der Container weiß, dass alles beieinander ist. Vergisst man das, so gibt's später eine Fehlermeldung.

Dort, wo der Motor benötigt wird, macht man nicht mehr
Delphi-Quellcode:
FMotor := TMotor.Create();
, sondern:
Delphi-Quellcode:
var
  aMotor : IMotor;
begin
  aMotor := ServiceLocator.GetService<IMotor>;
  aMotor.Brumm;
Das ist erst einmal schon alles. Damit man nicht die Unit uMotor einbinden muss, sollte die Interface-Deklaration von IMotor in eine eigene Unit ausgelagert werden. Bei mir sieht das z.B. so aus:
Delphi-Quellcode:
unit uInterfaces;

interface

uses
  Classes, SysUtils,

  uMotor, uBlinker
  ;

  procedure DI_Build;

type
  IMotor = uMotor.IMotor;
  function DI_Motor : IMotor;
type
  IBlinker = uBlinker.IBlinker;
  function DI_Blinker : IBlinker;

implementation

uses
  Spring.Container,
  Spring.Services;

procedure DI_Build; begin GlobalContainer.Build; end;

function DI_Motor : IMotor;
begin
  Result := ServiceLocator.GetService<IMotor>;
end;

function DI_Blinkr : IBlinker;
begin
  Result := ServiceLocator.GetService<IBlinker>;
end;
Mit Einbindung von uInterface braucht man in der aufrufenden Unit keine speziellen Units von Spring oder Motor einzubinden. Damit sind die Klassen vollständig entkoppelt. Das einzige Bindglied ist der DI-Container und der löst alles über Interfaces auf.

Mein typischer Aufruf sieht dann bspw. so aus:
Delphi-Quellcode:
var
  aMotor : IMotor;
begin
  aMotor := DI_Motor;
  aMotor.Brumm;
Der Spring-Container erfüllt dabei mehrere Funktionen: Er erzeugt die angeforderte Klassen, verwaltet deren Instanzen und gibt sie damit auch wieder frei. Die mitgelieferten Spring-Beispiele zeigen die weiteren Möglichkeiten. Mein Beispiel sollte nur zeigen, wie einfach der Einstieg sein kann und dass die Spring-Funktionalität sich nicht zu sehr aufdrängt.

Wofür das alles nun? Dadurch, dass an der Stelle, wo IMotor eingesetzt wird, nichts über TMotor und deren Unit bekannt sein muss, kann mann natürlich alles mögliche bereitstellen, solange es IMotor implementiert und damit die Prozedur Brumm() ausführen kann. Ganz klar auch, dass das Brummen im Motor-Teil erfolgen muss. An der konsumierenden Stelle hat man nichts über das Motor-Management zu wissen.

Nun ist der Motorwechsel einfach(er) und auch der Test eines Autos mit einem anderen oder Hilfs-Motor sollte kein Problem darstellen.

HTH.

Jens01 13. Feb 2012 14:21

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Ja, das habe ich soweit verstanden.
Bei mir hat sich aber ein anderes Problem dabei aufgetan.
Um bei Deinem Beispiel zu bleiben:
Es gibt jetzt eine Liste mit verschiedenen Autos und die Autos haben jeweils unterschiedliche Motoren.
Bei mir ist es jetzt so, wenn ich die Motoren mit "AsSingleton" registiere, dann haben alle Autos denselben Motor.

neo4a 13. Feb 2012 14:23

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von Jens01 (Beitrag 1150806)
Bei mir ist es jetzt so, wenn ich die Motoren mit "AsSingleton" registiere, dann haben alle Autos denselben Motor.

Dann lasse das .AsSingleton weg, dann bekommt jedes Auto seinen eigenen Motor (.AsTransient).

Jens01 13. Feb 2012 14:31

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Ja, okay, dann geht es aber innerhalb eines einzelnen Autos nicht mehr.

neo4a 13. Feb 2012 14:46

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von Jens01 (Beitrag 1150813)
Ja, okay, dann geht es aber innerhalb eines einzelnen Autos nicht mehr.

Ich benötige mehr Infos, eventuell konkrete Implementierungs-Details.

Ansonsten, wenn Du so initialisierst:
Delphi-Quellcode:
GlobalContainer.RegisterComponent<TMotor>.Implements<IMotor>;
dann ersetzt Du
Delphi-Quellcode:
var
  aMotor : TMotor;
begin
  aMotor := TMotor.Create();
mit
Delphi-Quellcode:
var
  aMotor : IMotor;
begin
  aMotor := ServiceLocator.GetService<IMotor>;
In beiden Fällen verweist aMotor auf eine spezielle Instanz.

exilant 13. Feb 2012 14:59

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von neo4a (Beitrag 1150796)
Wofür das alles nun? Dadurch, dass an der Stelle, wo IMotor eingesetzt wird, nichts über TMotor und deren Unit bekannt sein muss, kann mann natürlich alles mögliche bereitstellen, solange es IMotor implementiert und damit die Prozedur Brumm() ausführen kann. Ganz klar auch, dass das Brummen im Motor-Teil erfolgen muss. An der konsumierenden Stelle hat man nichts über das Motor-Management zu wissen.
Nun ist der Motorwechsel einfach(er) und auch der Test eines Autos mit einem anderen oder Hilfs-Motor sollte kein Problem darstellen.
HTH.

Autobeispiele sollten nicht mehr gewählt werden :-). Aber ich bleibe mal im Bild: Die Hierarchie haben wir jetzt vom Motor bis zum Fuhrparkleiter. Der will vielleicht nicht wissen wie der Motor im Wagen xy Brumm! macht, aber schon ob er Diesel oder Super will. Das muss er nämlich für seine Einsatzplanung bestellen. Das muss ich dem TFuhrparkleiter dann wieder über DI hintenrum mitteilen, oder wie? Obendrein sollte er noch die Betriebsstunden kennen, oder den Abschmierintervall um seinen Verfügbarkeitsplan aufzustellen. Aber der konsumierende muss ja nichts wissen...
Das ist mein Punkt. Und wenn ich am Ende angelangt bin, ist die ganze schöne Entkoppelung im Eimer. Oder habe ich da jetzt fundamental was nicht verstanden?

BUG 13. Feb 2012 15:03

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von exilant (Beitrag 1150819)
Der will vielleicht nicht wissen wie der Motor im Wagen xy Brumm! macht, aber schon ob er Diesel oder Super will. Das muss er nämlich für seine Einsatzplanung bestellen.

Meine Lösung wäre:
Der Fuhrparkleiter fragt das Auto, was es für Sprit will, das fragt den Motor und der muss es schließlich wissen.

Jens01 13. Feb 2012 15:10

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Delphi-Quellcode:
   AutoListe: TList<TAuto>;
type

  TAuto = class
    Test1: TMotorTest1;
    Test2: TMotorTest2;
  end;

  IMotor = interface
    function GetSchraubenAnzahl: Integer;
    procedure SetSchraubenAnzahl(const Value: Integer);
    procedure Brumm;
    property SchraubenAnzahl: Integer read GetSchraubenAnzahl write
  end;

  TMotor = class(TInterfacedObject, IMotor)
    function GetSchraubenAnzahl: Integer;
    procedure SetSchraubenAnzahl(const Value: Integer);
    FSchraubenAnzahl: Integer;
    procedure Brumm;
    property SchraubenAnzahl: Integer read GetSchraubenAnzahl write SetSchraubenAnzahl;
  end;

  TMotorTest1 = class
    Motor: IMotor;
    constructor Create;
    procedure Motortest;
  end;

  TMotorTest2 = class
    Motor: IMotor;
    constructor Create;
    procedure Motortest;
  end;

  TAuto = class
  public
    Test1: TMotorTest1;
    Test2: TMotorTest2;
  end;

implementation


constructor TMotorTest1.Create;
begin
  Motor := ServiceLocator.GetService<IMotor>;
end;

constructor TMotorTest2.Create;
begin
  Motor := ServiceLocator.GetService<IMotor>;
end;

initialization
  GlobalContainer.RegisterComponent<TMotor>.Implements<IMotor>.AsSingleton;
So, ich hoffe der Code ist richtig und verständlich.
Die Schraubenanzahlin Test1 und Test2 sind immer dieselben, was auch richtig ist, da es um denselben Motor geht.
Wenn jetzt aber das Auto in der Liste ist, dann ist die Schraubenanzahl bei jedem Auto immer noch dieselbe, aber jedes Auto hat einen anderen Motor mit einer anderen Schraubenanzahl.

stahli 13. Feb 2012 15:40

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Hallo Andreas, vielen Dank nochmal!

Also das mit den Interfaces ist beschlossene Sache! :-)
Das werde ich auf jeden Fall angehen und mein Projekt in absehbarer Zeit überarbeiten. Man verbirgt dadurch natürlich wunderbar das ganze interne Klassen-Geraffel und kann sich bei der Verwendung schön auf die "veröffentlichten Schnittstellen" beschränken.
Auch ist es egal, um was für Objekte es sich handelt, da nur noch wichtig ist, welche Schnittstellen sie haben.
Feine Sache - hätte man ja auch schon mal früher verstehen können. :stupid:

Deine Spring-Erklärung klingt eigentlich auch reizvoll, wobei ich noch skeptisch bin, wie flexibel das Ganze ist.
Wenn ich einem Auto einen V4-, V6- oder V8- Motor und wahlweise normales Licht oder Kurvenlist anbauen will und es eine Version mit oder ohne Zierleiste gibt, würde man das alles in dem GlobalContainer.RegisterComponent angeben?

Klassischer Weise würde ich (nach meinen aktuellen Vorstellungen) ein Auto-Interface erzeugen und dann einen bestimmten Motor, Licht und evtl. Zierleiste zuweisen. Dann wäre das Auto fertig.
Das ginge natürlich auch ohne Spring, statt dessen hätte ich eine Unit uWerkstatt, die eine Bestellung erhält und das Auto(-Interface) liefert.

Die von Dir (zu Recht) gelobte starke Entkopplung der Komponenten könnte ich durch die Interfaces dann ja auch (fast genau so gut) realisieren.


Mein Problem bei meinen Überlegungen stellt sich für mich folgender Maßen:

Ich habe z.B. Mannschaften, die Mitglieder enthalten und die wieder die Instanz einer Person. Eine Person hat u.a. einen Status (spielt/bereit/verletzt).

In verschiedenen Turnieren sind Spieler enthalten, die eine Personenreferenz (auf die Person eines o.g. Vereinsmitgliedes) haben. Die Spieler können in den unterschiedlichen Turnieren unterschiedliche Punkte erspielen und unterschiedliche Statusse haben. Z.B. kann ich in dem einen Turnier bereits gewonnen haben (ok, ist unrealistisch, aber ja nur ein Beispiel :-)) und im anderen aktuell gerade noch spielen. Es sind also verscheidene Spieler-Objekte, die die gleiche Person referenzieren.

Solche Bezüge gibt es viele und in noch komplexerer Form.

Diese Bezüge müssen beim Öffnen einer gespeicherten Turnierveranstaltung natürlich auch wieder hergestellt werden.

Jetzt stellt sich mir die Frage (egal ob mit Spring oder "nur Interfaces") wie sich solche Dinge sinnvoll handeln lassen.

Ich müsste also sogen können:

Delphi-Quellcode:
IPlayer := GetPlayerWithPersonId(12345, InTournament(23456));
Die Funktion müsste dann ermitteln, ob es einen solchen Spieler bereits gibt und ihn sonst neu anlegen.

Bietet Spring dafür Funktionalitäten?

Von der Owner-Verschachtelung werde ich mich wohl auf jeden Fall lösen müssen (wie Stevie beschrieben hat), aber damit kann man sicher gut leben. Die Objekte haben dann eben Bezüge, wie sie in einer relationalen DB abgebildet werden, was dann natürlich auch wieder eine Datenspeicherung in einer solchen erleichtern könnte.

Es kribbelt jedefalls schon ziemlich in den Fingern... :thumb:

neo4a 13. Feb 2012 15:43

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von Jens01 (Beitrag 1150825)
Delphi-Quellcode:
initialization
  GlobalContainer.RegisterComponent<TMotor>.Implements<IMotor>.AsSingleton;
So, ich hoffe der Code ist richtig und verständlich.
Die Schraubenanzahlin Test1 und Test2 sind immer dieselben, was auch richtig ist, da es um denselben Motor geht.
Wenn jetzt aber das Auto in der Liste ist, dann ist die Schraubenanzahl immer noch dieselbe, aber jedes Auto hat einen anderen Motor mit einer anderen Schraubenanzahl.

In Deinem Code lässt Du nur einen Motor zu. Lässt Du das AsSingleton wie vorgeschlagen weg, so gibt's mehrere Motoren.

Hinweis 1: Bei Spring brauchen die Interface-Deklarationen immer eine GUID, sonst gehen (intern) sämtliche Supports-Aufrufe nicht.

Hinweis 2: Spring verwaltet die Lifetime nur von AsSingleton-Interfaces. D.h. man benötigt bei AsTransient unbedingt eine Basisklasse, welches RefCounting implementiert.

(basierend auf Hinweisen von Stefan).

exilant 13. Feb 2012 15:44

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von BUG (Beitrag 1150821)
Meine Lösung wäre:
Der Fuhrparkleiter fragt das Auto, was es für Sprit will, das fragt den Motor und der muss es schließlich wissen.

Klar. Das geht. Nur warum ist

if fuhrpark.eingeteiltesfahrzeug.motor.kraftoffart = diesel then einkaufsabteilung.dieselbestellen;

schlechter Stil? Genau das behauptet Demeter. Entkopplung ist Mythos.
Als Ausnahme lasse ich in der Tat nur die Entkopplung von GUI/BL gelten. Und auch da nur bedingt.

Jens01 13. Feb 2012 15:59

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von neo4a (Beitrag 1150840)
In Deinem Code lässt Du nur einen Motor zu.

Ja, da ist für TAuto auch richtig, da es im Auto auch nur einen Motor gibt.
Zitat:

Lässt Du das AsSingleton wie vorgeschlagen weg, so gibt's mehrere Motoren.
Ja, dann funktioniert es für die Liste aber nicht mehr innerhalb von TAuto.

neo4a 13. Feb 2012 16:02

AW: Spring-DI / DelegatedConstructor / Factory für Dummies
 
Zitat:

Zitat von exilant (Beitrag 1150819)
Die Hierarchie haben wir jetzt vom Motor bis zum Fuhrparkleiter.

Der Interface-Ansatz kennt m.E. keine Hierarchien: Beide (TFuhrparkLeiter, TMotor) existieren unabhängig voneinander, sogar im richtigen Leben ;)

Zitat:

Zitat von exilant (Beitrag 1150819)
Der will vielleicht nicht wissen wie der Motor im Wagen xy Brumm! macht, aber schon ob er Diesel oder Super will. Das muss er nämlich für seine Einsatzplanung bestellen. Das muss ich dem TFuhrparkleiter dann wieder über DI hintenrum mitteilen, oder wie?

DI hat nur etwas mit Abhängigkeiten (Dependencies) zu tun. Damit also TFuhrparkleiter erfahren kann, ob aMotor Diesel will, muss er keinen Bauplan ala aMotor := TMotor.Create() haben, sondern er fragt das Etikett(Interface) aMotor : IMotor. Dort sollte es drauf stehen, erzeugt/gebaut wird der Motor woanders.


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

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