AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Algorithmen, Datenstrukturen und Klassendesign Delphi Spring-DI / DelegatedConstructor / Factory für Dummies
Thema durchsuchen
Ansicht
Themen-Optionen

Spring-DI / DelegatedConstructor / Factory für Dummies

Ein Thema von stahli · begonnen am 2. Feb 2012 · letzter Beitrag vom 15. Mär 2012
Antwort Antwort
Seite 1 von 2  1 2      
neo4a

Registriert seit: 22. Jan 2007
Ort: Ingolstadt
362 Beiträge
 
Delphi XE2 Architect
 
#1

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

  Alt 13. Feb 2012, 14:02
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:
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 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.
Andreas

Geändert von neo4a (13. Feb 2012 um 16:30 Uhr) Grund: Interface bei Spring unbedingt mit GUID ausführen!
  Mit Zitat antworten Zitat
Jens01

Registriert seit: 14. Apr 2009
674 Beiträge
 
#2

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

  Alt 13. Feb 2012, 14:21
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.
Achtung: Bin kein Informatiker sondern komme vom Bau.
  Mit Zitat antworten Zitat
neo4a

Registriert seit: 22. Jan 2007
Ort: Ingolstadt
362 Beiträge
 
Delphi XE2 Architect
 
#3

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

  Alt 13. Feb 2012, 14:23
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).
Andreas
  Mit Zitat antworten Zitat
Jens01

Registriert seit: 14. Apr 2009
674 Beiträge
 
#4

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

  Alt 13. Feb 2012, 14:31
Ja, okay, dann geht es aber innerhalb eines einzelnen Autos nicht mehr.
Achtung: Bin kein Informatiker sondern komme vom Bau.
  Mit Zitat antworten Zitat
neo4a

Registriert seit: 22. Jan 2007
Ort: Ingolstadt
362 Beiträge
 
Delphi XE2 Architect
 
#5

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

  Alt 13. Feb 2012, 14:46
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:
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.
Andreas
  Mit Zitat antworten Zitat
Jens01

Registriert seit: 14. Apr 2009
674 Beiträge
 
#6

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

  Alt 13. Feb 2012, 15:10
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.
Achtung: Bin kein Informatiker sondern komme vom Bau.

Geändert von Jens01 (13. Feb 2012 um 15:27 Uhr)
  Mit Zitat antworten Zitat
neo4a

Registriert seit: 22. Jan 2007
Ort: Ingolstadt
362 Beiträge
 
Delphi XE2 Architect
 
#7

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

  Alt 13. Feb 2012, 15:43
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).
Andreas
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.358 Beiträge
 
Delphi 11 Alexandria
 
#8

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

  Alt 13. Feb 2012, 15:40
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.

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:

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...
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
exilant

Registriert seit: 28. Jul 2006
134 Beiträge
 
Delphi 11 Alexandria
 
#9

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

  Alt 13. Feb 2012, 14:59
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?
Anything, carried to the extreme, becomes insanity. (Exilant)
  Mit Zitat antworten Zitat
Benutzerbild von BUG
BUG

Registriert seit: 4. Dez 2003
Ort: Cottbus
2.094 Beiträge
 
#10

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

  Alt 13. Feb 2012, 15:03
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.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:00 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-2025 by Thomas Breitkreuz