Kapselung Wie würdet ihr ein Service Layer erreichbar machen ...

X5-599

Top Contributor
... wenn Dependency Injection nicht möglich ist?

Hallo zusammen,

Ich habe also mein bestes getan, um meine Persistenz für eine Desktop Anwendung nach den allgemeinen Vorgehensweisen aufzubauen (so allgemein gehalten wie möglich; keine Singletons; klare Aufgabentrennung etc).

Service -> DAO -> Datenbank(per Hibernate)

Ich würde jetzt die Instanzen (Service und DAOs) beim Programmstart erzeugen, müsste diese aber irgendwie zugängig machen. Meine Controller sollen ja schießlich damit arbeiten.

Da es ja gilt Singletons bzw. statische Zugriffe zu vermeiden, würde ich davon absehen die Services einfach nur in einer statischen Map zu halten. Dann käme mir aber nur noch in den Sinn allen Controllern per Konstruktor oder Setter eine solche Map mitzugeben.

Wie würdet ihr das angehen?
 

X5-599

Top Contributor
Wieso nicht in jedem Controller einfach: Service service = new Service();

Dann müsste ich jedem Controller die DAOs als Abhängigkeiten übergeben. Denn die Services benutzen diese. Problem dabei ist: Jedes DAO benötigt die Hibernate SessionFactory. Und das ist halt ziemlich teuer. Und wenn ich richtig informiert bin sollte man dieses Objekt auch nicht mehrmals erzeugen?




Warum ist das nicht möglich?

Dein eigener Lösungsvorschlag ist doch schon DI (wobei man statt Map besser einfach die Objekte übergeben kann):

Ist halt die Vorgabe für das Projekt. Kein DI Framework als Dependency.


Um etwas mehr Code zu zeigen. So sieht es momentan aus;
Code:
SessionFactory sessionFactory = new Configuration().configure("hibernate.cfg.xml").buildSessionFactory();

EmployeeDao employeeDao = new EmployeeDaoImpl(sessionFactory);
EmployeeService service = new EmployeeServiceImpl(employeeDao);

So würde ich jetzt alle Services die meine Anwendung hat beim Programmstart erzeugen und dem ersten Controller übergeben. Als Map wäre leichter als jeweils einzelne Fields. Der Gedanke ist: Sollte ich andere Controller erzeugen müssen, würde ich einfach nur jeweils diese Map weiterreichen. So hätte jeder weitere Controller Zugriff auf alle Services.

Ich hatte es mir so gedacht, dass ich jeweils einen Controller pro View habe. Oder würdet ihr eher zu nur einen einzigen Controller raten? In dem Fall wären einzelne Setter für die Services beim Controller durchaus vertretbar.
Code:
controller.setEmployeeService(EmployeeService eService);
controller.setCompanyService(CompanyService cService);
// etc
 

mrBrown

Super-Moderator
Mitarbeiter
Ist halt die Vorgabe für das Projekt. Kein DI Framework als Dependency.
Erstmal: Dependency Injection != Framework.
Jeder Setter und Konstruktor, mit dem du Abhängigkeiten übergibst, ist DI. Alles, was du beschreibst, ist DI.


Woher kommt denn die Anforderung "Kein DI Framework"? Wenn man gleichzeitig sowas großes wie Hibernate einsetzt, wirkt das Verbot von zig Libs/Frameworks etwas unüberlegt...


Als Map wäre leichter als jeweils einzelne Fields. Der Gedanke ist: Sollte ich andere Controller erzeugen müssen, würde ich einfach nur jeweils diese Map weiterreichen. So hätte jeder weitere Controller Zugriff auf alle Services.
Mit der Map machst du es gleichzeitig deutlich schwerer zu warten und zu testen, weil man nie weiß, was ein Controller jetzt überhaupt benutzt. (Was man aber machen kann, ist eine Map<Class, Object> an einer zentralen Stelle, von wo aus sie auch nie weiter gegeben wird)
Wenn das zu viele Felder werden, ist das meist ein Zeichen für schlechtes Design.

Ich hatte es mir so gedacht, dass ich jeweils einen Controller pro View habe. Oder würdet ihr eher zu nur einen einzigen Controller raten?
Generell ist ein Controller per View besser, es muss aber nicht zwingend eine eins-zu-eins-Zuordnung zu Views geben.

In dem Fall wären einzelne Setter für die Services beim Controller durchaus vertretbar.
Die meisten bevorzugen Konstruktur-Injektion, damit bekommt man den Compile-Time-Check, dass alles übergeben ist. Bei Settern weiß man nie, welche nötig sind und ob man alle erwischt hat und arbeitet entgegen des "Konstruktor lässt das Objekt in einem validen Zustand"-Prinzips.
 

Flown

Administrator
Mitarbeiter
Dann müsste ich jedem Controller die DAOs als Abhängigkeiten übergeben. Denn die Services benutzen diese. Problem dabei ist: Jedes DAO benötigt die Hibernate SessionFactory. Und das ist halt ziemlich teuer. Und wenn ich richtig informiert bin sollte man dieses Objekt auch nicht mehrmals erzeugen?
Na klar, dein Beispiel war so generisch, dass ich auch nur so geantwortet hatte.

Es bietet sich hier an, dass du eine Factory übergibst, der dir die richtigen Dependecies bereitstellt (dann kannst du das ach testen).
 

X5-599

Top Contributor
Erstmal: Dependency Injection != Framework.
Jeder Setter und Konstruktor, mit dem du Abhängigkeiten übergibst, ist DI. Alles, was du beschreibst, ist DI.

Ja sorry. Für mich war DI bisher das was Spring zb macht. "Objekt Erzeugung per Annotation". Autowired und so. Konventionelle Objekt Erzeugung und Weitergabe lief für mich mit unter Objekt Orientierung...

Woher kommt denn die Anforderung "Kein DI Framework"? Wenn man gleichzeitig sowas großes wie Hibernate einsetzt, wirkt das Verbot von zig Libs/Frameworks etwas unüberlegt...

Gehört halt in diesem Haus nicht zu den "Standardwerkzeugen". Außerdem hab ich noch nie mit sowas gearbeitet und den ersten "Schuss" gleich in einem aktuell aktiven Projekt ... ist mir etwas zu heikel. Werde mir das aber mal ansehen. Ist schon komfortabel wenn man solche Abhängigkeiten nicht durch alle Klassen "durchschleifen" muss, sondern es einfach "dem System" überlasst diese bei Bedarf zu erzeugen.

Mit der Map machst du es gleichzeitig deutlich schwerer zu warten und zu testen, weil man nie weiß, was ein Controller jetzt überhaupt benutzt. (Was man aber machen kann, ist eine Map<Class, Object> an einer zentralen Stelle, von wo aus sie auch nie weiter gegeben wird)

Das Thema Testbarkeit kam öfters auf bei meinen Recherchen. Die will ich auch unbedingt erhalten. Verstehe auch deinen Einwandt, dass man bei einer Map natürlich nicht weiß welche Services denn nun gebraucht werden um einen bestimmten Controller zu testen. Aber du schreibst weiter, dass eine Map an einer zentralen Stelle gehen würde. Die müsste dann doch auch alle Services enthalten. Also wäre es doch nur ein Unterschied ob man die Map an die Controller per Konstruktor mitgibt oder diese Map statisch zugreifbar macht.

Die meisten bevorzugen Konstruktur-Injektion, damit bekommt man den Compile-Time-Check, dass alles übergeben ist. Bei Settern weiß man nie, welche nötig sind und ob man alle erwischt hat und arbeitet entgegen des "Konstruktor lässt das Objekt in einem validen Zustand"-Prinzips.


Das lässt sich nachvollziehen und ich denk mal es wird wohl bei mir darauf hinauslaufen. Allerdings hört sich das hier auch interessant an:


Es bietet sich hier an, dass du eine Factory übergibst, der dir die richtigen Dependecies bereitstellt (dann kannst du das ach testen).


Aber wäre das nicht (überspitzt ausgedrückt) eine glorifizierte Map mit allen möglichen Dependencies?
 

mrBrown

Super-Moderator
Mitarbeiter
Gehört halt in diesem Haus nicht zu den "Standardwerkzeugen".
Huch, sowas gibts noch? :p

Außerdem hab ich noch nie mit sowas gearbeitet und den ersten "Schuss" gleich in einem aktuell aktiven Projekt ... ist mir etwas zu heikel. Werde mir das aber mal ansehen. Ist schon komfortabel wenn man solche Abhängigkeiten nicht durch alle Klassen "durchschleifen" muss, sondern es einfach "dem System" überlasst diese bei Bedarf zu erzeugen.
Man kann für den Einstieg auch was "leichtgewichtigeres" wie Dagger oder Guice nutzen, das bringt weniger Magie als zB Spring oder CDI mit, das machst uu einfacher.

Aber du schreibst weiter, dass eine Map an einer zentralen Stelle gehen würde. Die müsste dann doch auch alle Services enthalten. Also wäre es doch nur ein Unterschied ob man die Map an die Controller per Konstruktor mitgibt oder diese Map statisch zugreifbar macht.
Die Map sollte nur an einer einzigen Stelle zugreizbar sein, an der, wo alles verbunden wird. Das kann während des Zusammenbringens der einzelnen Teile einfacher sein.
In den einzelnen Klassen hat die nichts zu suchen, die sollten nur die Objekte bekommen, die sie braucht.
 

X5-599

Top Contributor
Huch, sowas gibts noch? :p

Eieiei, was könnt' ich dir da erzählen... Würde hier aber wohl zu weit führen.


Die Map sollte nur an einer einzigen Stelle zugreizbar sein, an der, wo alles verbunden wird. Das kann während des Zusammenbringens der einzelnen Teile einfacher sein.
In den einzelnen Klassen hat die nichts zu suchen, die sollten nur die Objekte bekommen, die sie braucht.

Ok. habe ich das jetzt richtig verstanden, dass bei dieser Variante allerdings der Nachteil ist, dass man die Dependencies versteckt? Man weiß somit nicht, dass man eine "globale" Map mit allen Services braucht um einen belieben Controller zu testen.

Wenn ich das so richtig verstanden habe würde ich kurz nochmal das in Betracht ziehen was @Flown gesagt hat. Man könne auch eine Factory übergeben. Hört sich ganz interessant an. Oder würde das auch in den Bereich: "In den einzelnen Klassen hat die nichts zu suchen, die sollten nur die Objekte bekommen, die sie braucht." fallen?

Unterschied wäre, dass eine Factory die Services erst bei bedarf erzeugen könnte (evtl mit Cachen) und eine Map bereits voll initialisiert sein müsste.

Während ich das hier so schreibe, muss ich sagen, hört sich das eigentlich ganz gut an. Eine Factory deren Implementierung per Interface jede Service Instanz erzeugen können muss und an die Controller per Konstruktor übergeben wird.

Ist das in etwa vertretbar? Oder missachte ich damit andere/schon besprochene Richtlinien?

@Flown
Danke für den Link. Das kannte ich überhaupt noch nicht.
 

Flown

Administrator
Mitarbeiter
Wenn ich das so richtig verstanden habe würde ich kurz nochmal das in Betracht ziehen was @Flown gesagt hat. Man könne auch eine Factory übergeben. Hört sich ganz interessant an. Oder würde das auch in den Bereich: "In den einzelnen Klassen hat die nichts zu suchen, die sollten nur die Objekte bekommen, die sie braucht." fallen?
Naja die einzelnen Controller erhalten im Konstruktor die Factory und ziehen sich dann das gewünschte als Members dann raus (ist halt ein Mischmasch aus Factory-Pattern und Builder-Pattern um es genau zu nehmen).
 

mrBrown

Super-Moderator
Mitarbeiter
Ok. habe ich das jetzt richtig verstanden, dass bei dieser Variante allerdings der Nachteil ist, dass man die Dependencies versteckt? Man weiß somit nicht, dass man eine "globale" Map mit allen Services braucht um einen belieben Controller zu testen.
Die Map ist in dem Fall nicht global, sondern lokal - deshalb hat sie auch keinen Nachteil.
Alles was sie ersetzt sind lokale (bzw Instanz-) Variablen. Das ganze ist so ein bisschen "DI-Framework für Arme".

Wenn ich das so richtig verstanden habe würde ich kurz nochmal das in Betracht ziehen was @Flown gesagt hat. Man könne auch eine Factory übergeben. Hört sich ganz interessant an. Oder würde das auch in den Bereich: "In den einzelnen Klassen hat die nichts zu suchen, die sollten nur die Objekte bekommen, die sie braucht." fallen?
Ich würde auch eine Factory vermeiden, damit versteckt man auch die einzelnen Abhängigkeiten der Klasse.

Im Idealfall kennt eine Klasse nur die Abhängigkeiten, die sie selbst braucht, und auch nur genau die.
Wenn man denen Map oder Factorys übergibt, sind die vom "umgebenden Code" abhängig. Factorys würde ich nur nutzen, wenn die Klasse neue Instanzen erzeugen soll - die Abhängigkeiten soll sie ja aber meist grad nicht selbst erzeugen.
 

X5-599

Top Contributor
Danke nochmal. Also, nachdem ich eine Nacht drüber geschlafen habe bin ich zu dem Schluss gekommen, dass es wohl die sauberste (einfachste) Variante wäre wenn man per DI-Framework die Dependencies deklariert und injiziert bekommt. Denn außer man übergibt jede Dependency explizit an die jeweils nutzende Klasse gibt es anscheinend immer wieder Kleinigkeiten, die eher unschön sind bzw. problematisch werden können. Also wenn man hier "globale" Maps, lokale Maps oder Factories nutzt.
 
Ich mach das auch immer über dependency injection... Ich weiss nicht, obs das in meiner Abwandlung offiziel gibt, aber ich mach das immer so:

Grundvoraussetzung ist, dass die Objekte in einem Baum organisiert sind, wobei jedes Objekt genau ein Elternobjekt hat. (Denke das ist die gebräuchlichste Form einer Objektstruktur)

Es gibt eine Objekt-Container-Klasse, die objekte nach typ zugänglich macht. (Wie das bei DependencyInjection so üblich ist)

Falls der Objekt-Container einen typ nicht kennt, fragt er das Objekt von seinem Eltern-Container ab.
Dadurch kannst du - wenn du ein Objekt im Objektcontainer registrierst - diese für alle Kindobjekte im Baum unterhalb des registrierenden Objekts zugänglich machen.

Im Konstruktor der DependencyInjectionNode Klasse brauchst du dementsprechend keine Ellenlangen Konstrukturparameter mit mords abhängigkeiten, die sich jeden Tag ändern mehr, sondern nur ein Argument 'Parent' vom Typ 'DependencyInjectionNode'.
 

mrBrown

Super-Moderator
Mitarbeiter
Im Konstruktor der DependencyInjectionNode Klasse brauchst du dementsprechend keine Ellenlangen Konstrukturparameter mit mords abhängigkeiten, die sich jeden Tag ändern mehr, sondern nur ein Argument 'Parent' vom Typ 'DependencyInjectionNode'.

Hast du dann eine Abhängigkeit von Domänen-Objekt zu DependencyInjectionNode oder sind deine Domänen-Objekte auch DependencyInjectionNode?


In beiden Fällen würde ich es nicht mehr Dependency Injection nenne, weil die Objekte sich ihre Abhängigkeiten selber besorgen.

DI ohne "ellenlangen Konstruktor" (der üblicherweise ein Zeichen für schlechtes Design ist) oder entsprechend viele Setter funktioniert keine DI.
 
Ja so wird das immer, wenn ich anfange über Design zu philosophieren - erst recht wenn man so provokative Fragen stellt. ;-) Hoffe es ist dir nicht zuviel zu lesen...

Objektorientiert oder Klassenorientiert?
Zunächst mal: Ich rede von einem objektorientierten Model, nicht von einem klassenorientierten. Ich meine, wenn man ein MVC Model hernimmt und sagt, dass der Controlleranteil relativ gerne klassenorientiert wird und das Model eher objektorientiert ist, wird klar was ich damit meine. Ich vertrete die ansicht, dass es in einem Objektorientierten Model relativ wenig alternativen des korrekten Designs gibt. In einem Klassenorientierten (Controller)-Model ist es relativ lose und wenig ausschlaggebend, in wieviele Klassen ich Verantwortlchkeiten verteile. In einem oo-model kann es fatal sein, statt einer klasse 2 zu haben oder statt 2 eine, da hier Kardinalitäten von essentieller Bedeutung sind.

DIC / DIN
Ich unterscheide zwischen DependendyInjectionContainer und DI_Node, der den ersteren aggregiert. Der Container ist sealed, d.h. er wird nicht abgeleitet.

DI-Anzahl Argumente

DI ist von der Idee her , eine Abhngigkeit durch eine Schicht zu schleusen, die keine Abhöngigkeit dazu hat. Nicht mehr. Warum sollte DI nur über Setter/Argumente funktionieren? Ich habe - ausser in den Domänenobjekten - so gut wie keine Setter erst recht nicht in der DI-Container Klasse. Du hast einen ServiceContainer. Das ist der einzigste Parameter für den Konstruktor / Methodenargument. Über diesen einen Parameter kannst du eine unendliche Menge an Parametern transportieren. Du musst halt über den Objektkontext und die verfügbaren Dienste Bescheid wissen. Das ist aber der Natur der Sache geschuldet. Ich habe den DI-Container in den DI-Node Klasse aggregiert. Als Parameter verwende ich den DI-Container nur als "SerializationContext". Es gibt auch keine (generierten) aBleitungen der DI-Container Klasse mit typisierten gettern oder settern bei mir. (Wie man es vl. in einigen DI-Frameworks machen könnte) Insofern gibt es bestimmt einige Anwendungen von DI, die sich darin unterscheiden. Microsoft verwendet irgendwo in MarkupExtension (WPF-Klasse) einen DI-Container als Parameter. Da musste auch wissen, was du willst. Im statischen Klassenmodel siehst du nicht, was es für dienste gibt. Klar, weil die Dienste pro Objekt gelten, nicht pro Klasse. (Das wäre eine nette Debugger-Erweiterung)

Domönenobjekte+Abhängigkeit von DI.

In einem c++ Projekt (asap-as static as possible) habe ich eine DI-Node Basisklasse, von der alle Controller-Klassen abgeleitet sind. Da gibt es eigentlich keine Domänenobjekte. ES ist nur ein Presentationlayer in einem MultiCore-Embedded System. (ca 400k Loc)

In dem WPF-Projekt ist so ziemlich alles von DI-Node abgeleitet in einer Klasse, die noch ein bisschen mehr macht, als nur DI. (ca 1.5mio loc - nicht die Klasse, die applikation ;-) ) Auch das "EntityObject" (OO-Db) ist davon abgeleitet, wenngleich ich hier relativ selten einen Dienst abfrage. Aber z.b. Python Scripts können Domänenobjekte abfragen, was in diesem UseCase sehr häufig gemacht wird.

Wenn ich alles ohne DI machen würde (das wäre mit dem design wg. der Abhängigkeiten gar nicht möglich), Dann hätte ich undendlich lange Konstruktoren. Deshalb Schlechtes Design?

Zustandekommen von Objektmodellen

Das Objektmodel ergibt sich bei Domänenobjekten bzw. von Objekten in einer OO-Db doch aus der Sachlage. Das lässt wenig Freiheit zu, was verkehrt zu machen. Eine finanzbuchhalterisches Rechnungsobjekt hat nunmal n Positionen wovon jede genau eine Rechnung hat. (Kardinalität 1:n), einen Debitor (n:1), einen Kreditor (n:1) usw. Da lässt sich wenig drehen. Wer Objektorientierung verstanden hat, für den gibt es wenig Freiheit, OO Modele falsch abzubilden. Da kanste höchstens die OO Welt auf einer Schicht aus Performancegründen verlassen. Damit man sie ein paar monate später fluchend wieder löschen tut.

In WPF Architkturen leitet sich das ViewModel-REcht starr aus der Oberfläche ab und muss iwie den Model-Layer andocken. Im Idealfall ist das ViewModel eine 1:1 abbildung aus den Domänenobjeten, die bei mir in einer Objektorientierten Datenbank gespeichert sind.

Andere, controller ähnliche Objekte wie ein Thread, der Graphen im Hintergrund berechnet sind global im Applikationsobjekt definiert sollen aber in allen ViewModels zur Verfügung stehen. Die Tiefe des ViewModels-Models ist bei mir recht tief. Wie willste da das "globale" Thread objekt an das tiefste Objekt im ViewModel transportieren, ohne DI oder globale objekte oder ellenlange konstrukturen?

Verantwortlichkeit getService/addService

Ja die Objekte (DI Node) besorgen sich ihre Abhängikeiten selber. Genauso registrieren sie ihre Dienste auch selber. (Paradigma der Eigenverantwortlichkeit)

Wenn du das nicht dependency Injektion nennen willst, solltest du zumindest in der Lage sein, einen sinnvolere Bezeichnung zu bennenen. Es folgt aber von der Idee her der DI. Warum sollte ich mir durch Anwendungen von DI von der IDee abbringen lassen?

Gutes oder schlechtes Design
Ich denke das Design bildet auf Domänenobjektebene die Realität korrekt ab, und auf den anderen Ebenen erfüllt es seinen Zweck. Ich kann "globale" Objekte definieren und Objekte auf jeder ebene der Hirarchie "überschreiben" wovon ich regen gebrauch mache. Registriert werden auch nicht Objekte, sondern Get-Funktionen. Das erlaubt eine automatische Aktualisierung falls sich Eingabewerte ändern. (Aus diesem Grund arbeite ich recht selten mit settern sondern fast überall mit LazyLoad und automatischer Aktualisierung über eine Property-Klasse)

Das WPF-Programm ist - zusammen mit der objektorientierten Datenbank - vergleichsweise langsam. Aber dafür sind die Tools recht mächtig. Aufgrund meiner Auslastung geht das gar nicht anders. Ich hab schon alleine mit den Datenbankupdates, die alle paar monate kommen, weil sich domänenobjekte ändern, 1500 Objekte ala "CreateField", "DeleteTable", "PopulateTable" usw. 80 Tabellen mit etwa 2000 Feldern alternativ über MSSQL oder SQLite verwaltet, um eine dritte DB anzubinden brauche ich vl eine knappe woche, designbedingt. Das griegste als einzelner Programmierer glaub nicht anders gestemmt. Und ich hab auch noch andere Projekte...
 
Zuletzt bearbeitet:

httpdigest

Top Contributor
Damit Leute einer Argumentation folgen können, ist es niemals hilfreich, eigene Begriffe wie "klassenorientiert" zu erfinden, dann davon auszugehen, dass Leute schon wissen werden, was man selber damit meint (landläufige Meinung ist: "klassenorientiert" = "ja, es gibt halt Klassen" - nur die gibt's ja bei OO auch) und basierend darauf eine überzeugende Argumentationskette aufzubauen, die deine Punkte unterstützt. Dadurch verwirrst du Leute eher nur.
 
Nun, wenn niemand was erfinden soll, dann darfste morgen mit dem Vierreck-rad zur Arbeit rutschen ^^. Abgesehen davon habe nicht ich den Begriff erfunden. (Ich habe ihn von einem Seminarleiter übernommen und in einem anderen Konzern nochmal gehört- es sind also mind. 3 Leute, die den Begriff verwenden und ich bin nicht der, der ihn "erfunden" hat ;-) )

Ich habe doch erklärt, was damit gemeint ist. Wer nicht weiss, was MVC ist und nicht versteht, wie das gemeint ist, der wird auch beim Rest der Ausführung recht wenig chancen haben.

Klassen orientiert heisst nicht "Ja Es gibt halt Klsasen".

Es ist vielmehr, dass du klassische, funktionale Programierung in Klassen kapselst. Das ist ein Riesen unterschied zu "echter" OO..

Ich hatte in einem Projekt ein Framework aus Controllern, Basisklassen usw. selbst in dem Projekt haben die Leute von Klassenorientierung gesprochen.
 
Zuletzt bearbeitet:

mrBrown

Super-Moderator
Mitarbeiter
Auf den Teil zu DI geh ich mal detailliert ein:
DI ist von der Idee her , eine Abhngigkeit durch eine Schicht zu schleusen, die keine Abhöngigkeit dazu hat.
Nein.
Dependency Injection ist, einem Objekt die Abhängigkeiten zu injizieren, die es braucht. DI kennt im Kern weder Schichten, noch Container, noch geht es dabei im "durchschleusen".

Warum sollte DI nur über Setter/Argumente funktionieren?
Weil Dependency Injection das injizieren (=übergeben) von Abhängigkeiten bedeutet. Wenn ich Abhängigkeiten nicht von außen übergeben kann (entweder über Konstruktor oder Setter), ich also keine "Dependencys injizieren" kann, kann man nicht mehr von reiner Dependency Injection sprechen.

Ich habe - ausser in den Domänenobjekten - so gut wie keine Setter erst recht nicht in der DI-Container Klasse.
Quasi schon per Definition sind DI-Container-Klassen kein Teil der Domänenobjekten - oder wo finden die sich in deiner Domäne? ;)

Du hast einen ServiceContainer. Das ist der einzigste Parameter für den Konstruktor / Methodenargument. Über diesen einen Parameter kannst du eine unendliche Menge an Parametern transportieren.
Ja, du übergibst einen Container - aber eben nicht die eigentlichen Abhängigkeiten der Klasse, sondern eine Klasse, die Abhängigkeiten (oder wie du es nennst, Services) auflösen (bzw "lokalisieren") kann -> einen Service Locator.



Wenn ich alles ohne DI machen würde (das wäre mit dem design wg. der Abhängigkeiten gar nicht möglich), Dann hätte ich undendlich lange Konstruktoren. Deshalb Schlechtes Design?
Jap.
Wenn durch das Design ein Objekt unendlich viele Abhängigkeiten hat, kann man das durchaus als schlechtes Design bezeichnen.


Das Objektmodel ergibt sich bei Domänenobjekten bzw. von Objekten in einer OO-Db doch aus der Sachlage. Das lässt wenig Freiheit zu, was verkehrt zu machen. Eine Rechnung hat nunmal Positionen in der Kardinalität 1:n, einen Debitor, einen Kreditor usw. Da lässt sich wenig drehen. Wer Objektorientierung verstanden hat, für den gibt es wenig Freiheit, OO Modele falsch abzubilden.
Dem würde ich zumindest in Teilen widersprechen.
Das eine, für alles Anwendungsfälle geeignete Domänemodell gibt es nicht. Eher gibt es viele, gleich richtige Domänenmodelle, die für unterschiedliche Teile eines Problems passend sind. Und resultierend daraus gibt es auch viele Freiheiten, was falsch zu machen.

(Gab grad bei Heise einen Artikel in die Richtung: https://www.heise.de/developer/arti...ls-Kontrapunkt-zu-Technical-Debt-4284588.html)

Im Idealfall ist das ViewModel eine 1:1 abbildung aus den Domänenobjeten
Bei mir ist das im üblichen Fall nicht so, eher eine n:n-Beziehung. Das ViewModell kann durchaus eine ganze Menge weniger Informationen enthalten, als das DM (und damit resultieren mehrere verschiedene Domänen-Objekte in dem gleichen ViewModel-Objekt), und andererseits gibt es für ein Domänen-Objekte durchaus mehrere verschiedene ViewModelle.

Andere, controller ähnliche Objekte wie ein Thread, der Graphen im Hintergrund berechnet sind global im Applikationsobjekt definiert sollen aber in allen ViewModels zur Verfügung stehen. Die Tiefe des ViewModels-Models ist bei mir recht tief. Wie willste da das "globale" Thread objekt an das tiefste Objekt im ViewModel transportieren, ohne DI oder globale objekte oder ellenlange konstrukturen?
Generell: anderes Design. Kann in dem speziellen Fall aber anders aussehen, muss man jeweils individuell beurteilen.
ServiceLocator (oder in dem Fall vielleicht Factory) sind ja auch keine verbotenen Pattern - aber es ist eben keine DI.

Ja die Objekte besorgen sich ihre Abhängikeiten selber. ÜBer Dependency Injection.
Den Widerspruch zwischen diesen "selbst besorgen" und "injiziert bekommen" merkst du aber schon noch selber? ;)

DI ist von der Idee her , eine Abhngigkeit durch eine Schicht zu schleusen, die keine Abhöngigkeit dazu hat.
Nein. DI ist von der Idee her, Abhängigkeiten zu übergeben.
(Durchschleusen von Abhängigkeiten versucht man dabei eher zu vermeiden.)

Wenn du das nicht dependency Injektion nennen willst, solltest du zumindest in der Lage sein, einen sinnvolere Bezeichnung zu bennenen.
Je nach Ausprägung zb Factory oder Service Locator.
 

mrBrown

Super-Moderator
Mitarbeiter
Nun, wenn niemand was erfinden soll, dann darste morgen mit dem Vierreck-rad zur Arbeit fahren. Abgesehen davon habe nicht ich den Begriff erfunden.

Ich habe doch erklärt, was damit gemeint ist.
Ehrlich gesagt hab ich keine Ahnung, was du damit meinst.

Deine Erklärung hat mich eher ratlos in die Luft blickend zurückgelassen, deshalb hab ich auch nichts Zuzu geschrieben. Hat ja auch nicht wirklich was mit dem Rest des Beitrags zu tun.
 

httpdigest

Top Contributor
Okay, du meinst also mit "klassenbasiert" = "Man hat eine Reihe von statischen Methoden und verwendet diese statt Instanzmethoden auf Instanzen der Klasse." Wäre doch ganz einfach gewesen, das so zu definieren.
Class-based/Class-oriented (konnte keinen deutschen Artikel zu "klassenorientiert" finden), bedeutet zumindest etwas ganz anderes (zumindest laut Wikipedia): https://en.wikipedia.org/wiki/Class-based_programming
tl;dr "Klassenorientiert" ist das Gegenteil zu "prototypenbasiert", also Vererbung durch Klassen statt durch Objekte/Prototypenketten (letztere zu finden in JavaScript).
 
oh ok... du hast ja doch recht viel geantwortet. ich mach mal weiter...

Weil Dependency Injection das injizieren (=übergeben) von Abhängigkeiten bedeutet. Wenn ich Abhängigkeiten nicht von außen übergeben kann (entweder über Konstruktor oder Setter), ich also keine "Dependencys injizieren" kann, kann man nicht mehr von reiner Dependency Injection sprechen.

Ich bin "schlecht" in java aber ich versuche zu skizieren:

// bereitstellung
public virtual DiContainer getDiContainer() {
if m_dicontainer == null {
DiContainer dic = base.getDiContainer().inherit(this);
di.addService<MyService>(()=>this.getMyService())
m_dicontainer = dic;
}
return m_dicontainer;
}

// verwenden:
this.Parent.getDiContainer().getService<IMyService>()

// und - weil this.servicecontainer = base.inherit ist geht auch - in jedem untergeordneten objekt:
this.getDiContainer().getService<...>()

Wenn durch das Design ein Objekt unendlich viele Abhängigkeiten hat, kann man das durchaus als schlechtes Design bezeichnen.
Es hat nicht unendlich viele Abhängigkeiten.Die Objekte die Dienste bereitstellen und die die diesen Dienst nutzen liegen nur weit auseinander. (An der Anzahl der Konstruktur aufrufe gemessen)

Das eine, für alles Anwendungsfälle geeignete Domänemodell gibt es nicht.
Das habe ich auch nicht behauptet.Lediglich, dass es für eine Gegebenheit (Rechnung<->Positionen) wenig alternativen für ein korrektes Design gibt.

Bei mir ist das im üblichen Fall nicht so, eher eine n:n-Beziehung.
Auweia... Ic

h meine hier nicht 1:1 im Sinne von Kardinalität. Eher so, dass es für jedes Objekt/Klasse/Beziehung des Model-Layers eine Objekt/Klasse/Beziehung gibt. Also nicht "asynchrones" Design.

Den Widerspruch zwischen diesen "selbst besorgen" und "injiziert bekommen" merkst du aber schon noch selber
Nun, ich identifiziere das objekt anhand der Klasse = Schlüssel aus dem DI-Container. Was ich injeziert bekomem ist das konkrete Objekt. Das kann eine abgeleitete klasse sein, die erstellt und gebaut wird, wovon ich alles nix weiss.

Aber mir wirds grad etwas zu blöd ehrlich gesagt. Ich glaube nicht, dass du verständnis suchst sondern eher das verkehrte. Aber ich mach dennoch weiter:

Nein. DI ist von der Idee her, Abhängigkeiten zu übergeben.
(Durchschleusen von Abhängigkeiten versucht man dabei eher zu vermeiden.)
Was verstehst du dann unter "Injection"? Nun, das durchschleussen von Abhängikeiten durch mehrere Ebenen eines ViewModels (MVVC) funktioniert recht gut. Wie gesagt, sagt mir wie dus anders lösen würdest , anstatt hier zu versuchen, meine Erörterung ad absurdum zu führen.

Damit schliesse ich.
 
Zuletzt bearbeitet:
Okay, du meinst also mit "klassenbasiert" = "Man hat eine Reihe von statischen Methoden und verwendet diese statt Instanzmethoden auf Instanzen der Klasse." Wäre doch ganz einfach gewesen, das so zu definieren.
Class-based/Class-oriented (konnte keinen deutschen Artikel zu "klassenorientiert" finden), bedeutet zumindest etwas ganz anderes (zumindest laut Wikipedia): https://en.wikipedia.org/wiki/Class-based_programming
tl;dr "Klassenorientiert" ist das Gegenteil zu "prototypenbasiert", also Vererbung durch Klassen statt durch Objekte/Prototypenketten (letztere zu finden in JavaScript).

Ja, könnte sein dass wir dasselbe meinen. In klassenorientierten Programmen findet man auch eine menge methoden argumente. Die kürzen sich in einem OO-model recht schnell weg, weil man zu den argumenten über member navigieren kann.

Es geistert halt viel durch konzerne was nicht öffentlich debatiert wird. Oder rausfliegt weils zuwenig offensichtlich ist. Wie gesagt, jetzt sind wir schon zu viert ^^ - mindestens
 

mrBrown

Super-Moderator
Mitarbeiter
Es hat nicht unendlich viele Abhängigkeiten.Die Objekte die Dienste bereitstellen und die die diesen Dienst nutzen liegen nur weit auseinander. (An der Anzahl der Konstruktur aufrufe gemessen)

Du hast also etwa solche Ketten (Großbuchstaben = Objekt, -> = kennt): A->B->C->D-E

Wenn jetzt Objekt A ein anderes Objekt X kennen muss, nur weil E ein X braucht, dann, ja, kann man das als schlechtes Design bezeichnen.
Es gibt für A schließlich keinen, aus der Domäne hervorgehenden Grund, X zu kennen - außer eben den technischen Grund, dass A X für E kennen muss, was es dabei selbst nicht mal kennt.

Das habe ich auch nicht behauptet.Lediglich, dass es für eine Gegebenheit (Rechnung<->Positionen) wenig alternativen für ein korrektes Design gibt.
Du hast leider den Rest des Absatzes unterschlagen, aber der wesentliche Punkt meiner Aussage war, dass es, anders als du sagst, sehr viele Freiheiten für Fehler gibt.
Auweia zurück?

Ich meine hier nicht 1:1 im Sinne von Kardinalität. Eher so, dass es für jedes Objekt/Klasse/Beziehung des Model-Layers eine Objekt/Klasse/Beziehung gibt. Also nicht "asynchrones" Design.
Keine Ahnung, was du mit asynchronem Design meinst, aber bei mir gibt es eben nicht für jedes Objekt/Klasse/Beziehung im Model-Layer eine entsprechende Objekt/Klasse/Beziehung in einem anderem Layer.
Schön, dass wir es noch mal anders formuliert haben.

Nun, ich identifiziere das objekt anhand der Klasse = Schlüssel aus dem DI-Container. Was ich injeziert bekomem ist das konkrete Objekt. Das kann eine abgeleitete klasse sein, die erstellt und gebaut wird, wovon ich alles nix weiss.
Der wesentliche Punkt dabei ist: Ein Objekt holen ist etwas anders als "injecten".

Du fragst aktiv nach etwas und bekommst es zurückgegeben. Das ist das Gegenteil von etwas passiv übergeben bekommen. (Als Beispiel: Dein Blut holt sich nicht von irgendwo die Impfung, sondern sie wird von außen injiziert. Die Gussform holt sich nicht den Kunststoff, sondern er wird von außen injiziert, ...)

Was verstehst du dann unter "Injection"?
Im diesem Kontext: das Übergeben/Einbringen von etwas.
Ganz generell: https://www.dict.cc/?s=inject

Nun, das durchschleussen von Abhängikeiten durch mehrere Ebenen eines ViewModels (MVVC) funktioniert recht gut. Wie gesagt, sagt mir wie dus anders lösen würdest , anstatt hier zu versuchen, meine Erörterung ad absurdum zu führen.
ich habe nie bezweifelt, dass es in deinem Fall gut funktioniert. Ich weiß selber, dass es in vielen Fällen gut funktioniert.

Nur sind eben deine Schlüsse falsch.

DI bedeutet nicht, dass Abhängigkeiten durchgeschleift werden.
Eher vermeidet man das dabei, geht ja auch erfreulich einfach und ist oftmals die bessere Lösung: Anstatt mir die Abhängigkeiten geben zu lassen, die irgendein "Kind-Objekt" hat (und damit Interna das Kind-Objekts kennen muss und Dinge tue, die die Klasse eigentlich nichts angehen [nämlich das zusätzliche Objekt, was ich durchschleife]), kann ich mir einfach das benutzbare Kind-Objekt geben lassen.
Das bedeutet im Umkehrschluss natrülich nicht, dass Abhängigkeiten durchschleifen keine DI sein kann. Wenn man Abhängigkeiten dann in ein Kind-Objekt injiziert, das das an der Stelle schon DI.

DI bedeutet nicht, das Objekte sich ihre Abhängigkeiten selber besorgen.
Sich die Abhängigkeiten selbst besorgen, ist keine DI, da die Abhängigkeiten nicht injiziert werden. Das ganze fällt wie gesagt eher unter Service Locator, Factory oder Singleton, je nach Ausprägung.
Nachteile, die das Abhängigkeiten selbst besorgen hat, stehen hier ja schon im Thread. uU muss man immer die Interna des Objekts kennen, da man nicht von außen sehen kann, was für Abhängigkeiten sie haben.



Hier übrigens ein Artikel von Fowler (der, der den Begriff DI geprägt hat) zu genau diesem Thema: https://martinfowler.com/articles/injection.html
Sowohl DI als auch Service Locator werden dort recht gut beschrieben.
 
enn jetzt Objekt A ein anderes Objekt X kennen muss, nur weil E ein X braucht, dann, ja, kann man das als schlechtes Design bezeichnen.

Genau, geh mal von einem Baum aus. ganz oben sitzt dein applikationsobjekt. (A) Das stellt einen Controller bereit, der im Hintergrundthread etwas berechnet. (T) Jetzt kommt ein DRive objekt (D), dannach ein Folder objekt (F), dannach ein "Folder-in-dem-man-ganz-bestimmte-domänenobjekte-anlegen-kann"-objekt. (F2) Dannach ein Domänenobjekt (Do) - das ist in meinem Falle eine Kennlinie. (Kennlinie aus prozessteuerung)

Die Objektstruktur sieht daher so aus:
A->D->F->F2->Do
A->T

jetzt hast du in dem DO Objekt eine Liniendiagramm, das im hintergrund berechnet wird. DAzu verwendet Do den Thead, den A erstellt hat. Denn es kann N Dos geben, die solche liniendiagramme beinhalten, aber ich will vielleicht nicht für jedes Do einen Thread aufmachen.

Soll ich jetzt das T als konstrukturparameter durch D, F, F2 schleussen, nur damit Do es nutzen kann? Dann hätten wir genau diese Mörderabhängigkeit von der du sprichst. Eine abhängigkeit, die nur existiert, weil ich das objekt an irgendjemand anderes weiterreichen muss, weil derjenige keine andere möglichkeit hat, ranzukommen. (Wenn ein Pfad gekapselt werden soll kann man das schon mal machen, aber meistens ist es unerwünscht)

Genau da benutze ich DI. Ich schleuse nämlich nur den Container durch D, F, und F2. Diese Container ist eine absolute grundlegende klasse, ohne Abhängigkeiten zu irgendwelchen, applikationsspezifischen As, D,s Fs, F2s, und Dos...

Jetzt klar was ich meine?
 
Zuletzt bearbeitet:
DI bedeutet nicht, dass Abhängigkeiten durchgeschleift werden.

Es beduetet, dass eine Abhängigkeit injiziert wird. Das sagt aber nichts über die Anzahl der schichten aus, durch die es injeziert (=Durchgeschleift) wird. (In deinem Biologie-Beispiel ist das Z.b. die Hautschicht, die kommt erstmal nicht mit dem Impfstoff in Berührung.).

Es ist aber mindestens 1 schicht, durch die es geschleift wird.

Diese mind. 1 Schicht hat keine Abhängigkeit zu dem injizierten Typ.

Wenn es keine Schicht gibt, durch die es injeziert wird, dann ist es per Definition keine DI, denn dann gibt es nix zu injezieren... :p
 

mrBrown

Super-Moderator
Mitarbeiter
Jetzt klar was ich meine?
Ja, schon von Anfang an.

Aber schön, dass du mein Beispiel nochmal mit anderen Buchstaben aufgeschrieben hast ;)

Soll ich jetzt das T als konstrukturparameter durch D, F, F2 schleussen, nur damit Do es nutzen kann?
Nein. Wie schon mehrmals geschrieben: Einfach nur Durchschleusen ist nicht sinnvoll, üblicherweise und grad auf mit DI gibt es bessere Weg.

Genau da benutze ich DI.
Den Container von F nach F2 weitergeben ist in dem Fall sogar fast DI. Den Container in DO benutzen aber eben nicht mehr - das ist Service Locator. (Und "fast DI" weil der Container keine "echte" Abhängigkeit der Objekte ist).


Um dafür eine schönere Lösungen ohne Durchschleifen eines Containers zu finden, müsste man mehr wissen.
zb, wie wird dieser Objektgraph aufgebaut, wo und wie wird der Chart gebraucht?
 
Nein. Wie schon mehrmals geschrieben: Einfach nur Durchschleusen ist nicht sinnvoll, üblicherweise und grad auf mit DI gibt es bessere Weg.

:p Ja. Nix anderes sag ich doch.... Ich rede doch die ganze zeit davon, mittels DI diese Abhängkeiten zu vermeiden...

Aber Naja. Der ServiceLocator... Den brauch ich doch nicht, wenn ich den ServiceContainer habe. Und Locaten tu ich in meiner Implementierung, indem jeder ServiceContainer einen Base-ServiceContainer hat. Dadurch "erbt" ein objekt alle diesnste seiner eltern und hat die möglichkeit, weitere Dienste bereitzustellen, die aber wiederrum nur für seine untergeordneten objekte gelten. [1]

Die Trennung zwischen Container und Locator wäre bei diesem Unterfangen eher hinderlich. Ich habe sone art locator innerhalb der Container Implementierung. Das ist aber im Endeffekt nur ein anonymer Methodenzeiger oder Delegate wie es in .NET genannt wird. In Java gibts sowas glaub auch, java kann ja auch lambda ausdrücke...
 

mrBrown

Super-Moderator
Mitarbeiter
Es beduetet, dass eine Abhängigkeit injiziert wird. Das sagt aber nichts über die Anzahl der schichten aus, durch die es injeziert (=Durchgeschleift) wird.
Richtig.
Und genau daraus folgt meine Aussage: Da es keine Aussage über das Durchschleifen gibt, impliziert DI nicht durchschleifen.

In deinem Biologie-Beispiel ist das Z.b. die Hautschicht, die kommt erstmal nicht mit dem Impfstoff in Berührung.
Offensichtlich sollten wir den Begriff "Schicht" noch klären. In diesem Beispiel, wäre die Haut als Grenze teil der "Adern/Venen-Schicht" (...sehr konstruiert, aber egal...), die haut gäbe es ohne Adern/Venen nicht, sind also keine eigene Schicht.

Es ist aber mindestens 1 schicht, durch die es geschleift wird.

Diese mind. 1 Schicht hat keine Abhängigkeit zu dem injizierten Typ.

Wenn es keine Schicht gibt, durch die es injeziert wird, dann ist es per Definition keine DI, denn dann gibt es nix zu injezieren... :p

Das wie gesagt sehe ich anders.
DI setzt üblicherweise drei Objekte voraus (Interfaces etc mal weggelassen):
* Das Objekt A, in das Injiziert wird
* Das Objekt B, welches Injiziert wird
* Das Objekt C, welches B in A injiziert (und zB den Lebenszyklus von B und/oder A verwaltet)

B ist offensichtlich keine Schicht, durch welche B durchgeschleift wird
A wäre in dem Modell eine Schicht. Allerdings hat es eine direkte Abhängigkeit zu B und nutzt B, B wird also nicht durch A durchgeschleift.
C ist der Container, der das ganze managed. Je nach Sichtweise kann man das als Schicht sehen. Aber wird B durch C durchgeschleift? C ist für den Lebenszyklus von B zuständig, von daher würde ich sagen, B wird nicht durch C geschleift.

Wir haben also keine Schicht, durch die B "geschleift" wird, und auch keine Schicht, die keine Abhängigkeit zu B hat - sehr wohl aber DI in seiner reinsten Form.
 

mrBrown

Super-Moderator
Mitarbeiter
:p Ja. Nix anderes sag ich doch.... Ich rede doch die ganze zeit davon, mittels DI diese Abhängkeiten zu vermeiden...
Doch, du schleifst *alle* Abhängigkeiten durch *alles* durch, und löst die Abhängigkeiten der Objekte eben nicht durch DI auf.

Aber Naja. Der ServiceLocator... Den brauch ich doch nicht, wenn ich den ServiceContainer habe.
Dein ServiceContainer *ist* ein ServiceLocator. Auch wenn du es anders nennst, ändert das nichts daran. Lies dir den geposteten Artikel von Fowler oder zB den Wiki-Artikel zu dem Thema durch.
 
* Das Objekt A, in das Injiziert wird
* Das Objekt B, welches Injiziert wird
* Das Objekt C, welches B in A injiziert (und zB den Lebenszyklus von B und/oder A verwaltet)

Deise Trennung hab ich aber auch so. Lediglich dass zumindest B und A meist diesselbe basisklasse haben, den DiNode. Und der Name Node ist nicht von ungefähr gewählt, es ist der Baum der entsteht wenn man betratchtet "Wer verwaltet den Lebenszyklus von wem".
 
Wir haben also keine Schicht, durch die B "geschleift" wird, und auch keine Schicht, die keine Abhängigkeit zu B hat - sehr wohl aber DI in seiner reinsten Form.

Nicht in der Minimaldefinition, wie du sie aufführst. Aber in der Praxis juckt es doch nicht, wieviele Schichte = Objekte dazwischen liegen. In meinem Beispiel liegen die Objekte D, F, F2 zwischen dem bereitsteller des Objekts (Server=dein b) und dem Client des Objekts (dein A).

Ich verwende den Begriff Server und Client für alles Mögliche.... Einfach als "Lieferant und kunde"
 
Dein ServiceContainer *ist* ein ServiceLocator. Auch wenn du es anders nennst, ändert das nichts daran. Lies dir den geposteten Artikel von Fowler oder zB den Wiki-Artikel zu dem Thema durch.

Ja hab den (deutschen) Wiki Artikel gelesen. [1] Fowler und GOF habe ich einige Jahre vor der VÖ des DI Patterns gelesen. Mir ist klar, dass jeder Konstruktor aufruf mit einem komplexen Typ von der Idee her eine DI ist. Aber so nennen würde ich das nicht. Die Welt geht ja noch weiter.

Ich hab damals das DI für mich erfunden, als ich eine Basisklasse in einem Konzern erweitert hatte. Der techn. Projektleiter meinte dann so "du, du hast da diese basisklasse erweitert aber Dependency Injection verwenden wir hier eigentlich nicht" Ich hab ihn fragend angeschaut, weil ich nicht wusste was er meinte. So kams dann, dass die Implementierung drinne blieb.... Will sagen: Ich bin gewiss, dass meine Implementierung DI ist. Auch wenn es andere populäre anwendungen gibt, die andere Klassen bennenen.

Ich wollte hier eigentlich nur meine Implementierung vorzustellen, mit der Idee, dass es Kontexte gibt, in denen Dienste verfügbar sind, die man - einmal registriert - an alle Kindobjekte "vererben" kann und diese wiederrum. dienste "überschreiben" und neue dazudefinieren können. Das ist die mächtigste Ausprägung des DI Patterns das ich kenne und es lässt sich auch sehr einfach, nur mit einer Basisklasse, einem Konstruktor und einer virtuellen Methode implementieren... ohne aufwendige Dictionaries oder Hastables oder anonymen delegates. (allerdings nicht misra conform ;)

Diese Basisklasse sieht in c++ z.b.so aus: (wie gesagt, die minimalst-implementierung)

class CDiNode {
private: CDiNode* mParentPtr;
CDiNode(CDiNode* aParentPtr) : mParentPtr(aParentPtr) {}
public: virtual void* GetServicePtr(ClassIdEnum aClassId) {
return this->mParentPtr ? this->mParentPtr->GetServicePtr(aClassId) : 0;
}
};

(hoffentlich hab ich keinen strichpunkt vergessen)
(hoffentlich regt sich jetzt keiner über den void* auf)
(Microsoft machts aber im Prinzip genauso - in .net lässt sich die typunsicherheit allerdings durch eine generische methode kapseln. In c++ über rtti auch, aber dann kann man keinen schnellen switch machen. daher ...)

Da der TE von einem Service-Layer sprach und die Frage stellte, wie man so einen Layer den Objekten ohne singleton zugänglich macht, denke ich, das passt genau.

Zum englischen Artikel, wo vermutlich die implementierung mit dem Locator beschrieben ist dringe ich heute nicht mehr vor. Aber das Inversion of Control Containers and the Dependency Injection pattern hört sich interesannt an

[1] https://de.wikipedia.org/wiki/Dependency_Injection
j
 
Dann solltest du gleichermaßen nicht davon ausgehen, dass irgendwer versteht, wovon du redest ;)
Alle anderen nennen genau das nämlich DI und das was du DI nennst Service Locator.

Wer mich verstehen will, der wird es verstehen. Du hingegen scheinst mich nur als Depp hinstellen zu wollen. DI ist eine Idee, so wie alle Pattern, zu denen es viele Implementierungen gibt und die Klassennamen sind oft nur exemplarisch.

Eigentlich solltest du deinen Titel von Super Moderator in Super Troll umbenennen. ;-)

Aber ist normal für viele Foren, dass wenn einer ankommt und nicht mit helloWorld anfängt da dann sofort das oberschlaule im Forum sich einen Konkurenzkampf liefert.

Brauchst dich aber nicht in deiner Kompetenzstellung bedroht zu fühlen. Ich schau hier nur eh alle paar jahre wieder einmal rein.

Tschüss.
 
Zuletzt bearbeitet:

mrBrown

Super-Moderator
Mitarbeiter
Du hingegen scheinst mich nur als Depp hinstellen zu wollen.
Nein, eigentlich war das keineswegs mein Ziel.

DI ist eine Idee, so wie alle Pattern, zu denen es viele Implementierungen gibt und die Klassennamen sind oft nur exemplarisch.
Zum Teil ja. Allerdings kannst du in jeder Implementierung alle Klassen eindeutig denen des Pattens zuordnen. Und eben das klappt bei deiner Implementierung nicht mehr.

Es ist ja auch keineswegs so, als wäre deine Lösung nicht auch ein bekanntes Pattern (bzw in seiner Gesamtheit sogar mehrere, Kompositum steckt da ja durchaus auch drin) oder irgendwie schlecht. Sie ist halt nur keine DI, sondern Service Locator.


Der Text von Fowler beschreibt beide Pattern ziemlich gut, und macht den Unterschied deutlich.

Die Unterscheidung magst du kleinlich finden, aber den Unterschied gibt es eben und für viele hier mitlesende ist der Unterschied relevant und ein Vermischen der beiden nur verwirrend.
 
Nein, eigentlich war das keineswegs mein Ziel.

Naja. Du provuzierst recht oft und noch öfter gehst du auf die Schwachstellen meiner Ausführungen "ein" und lässt den Rest aussen vor, dabei willst du oft das falsche verstehen und dich hervortun, indem du behauptest was deiner meinung nach richtig ist, wobei oft nur um begrifflichkeiten gestritten wird. Ich könnte jetzt anfangen, alles mit "dont feed the troll" zu zitieren/kommentieren. Wär vl. gar nicht mal so schlecht.

Programmierer A: Ey, ich injecte ein C durch constructor injection in mein B und das mache ich in dem ich von der Klasse namens "Injector" die Factory Funktion "new" verwende.

Programmierer B: Das B-Objekt wird von A mit dem B-Objekt als Konstruktorparameter instanziert.

Was macht mehr sinn? Es gibt bereits grundlegendere Begrifflichkeiten dafür, was hier passiert. Dass das vom Ürinzip her "auch schon" DI ist, ist lediglich ein Auftakt für Fowlers ausführungen. Und dass es wirklich DI ist, stelle ich in frage für alle sprachen, die keine Forwarddeklaration können. (Da gibt es kein "NOINN DAS IST NICHT SO" da gibt es nur ein "verstanden, warum ich das sage?")

Nicht nur für mich fängt DI da an, wo Objekte durch container gekapselt und anhand des Typs identifiziert werden, um sie durch schichten zu schleusen (injecten) die keine Abhängkeit (dependency) zu diesen Typen kennen.

Wenn du meinst, dass das was ich service container nennen eigentlich ein service locataor ist, dann erkläre mir doch bitte, was dann ein service container ist. (Meine Implementierung hat wahrscheinlich aspekte von beidem)

 
Zum Teil ja. Allerdings kannst du in jeder Implementierung alle Klassen eindeutig denen des Pattens zuordnen. Und eben das klappt bei deiner Implementierung nicht mehr.

Es gab mal ein Bild mit etwa 40 pattern, die mit using/Extends in beziehung gesetzt wurden. Ich hab allerdings keinen Plan, wer dieses geniale Bild in die Welt gesetzt hat und wo es zu finden ist. Das sind für mich pattern, die du kombinieren, implementieren aber niemals (oder sehr selten wie beim observer pattern) (in basisklassen) kapseln kannst. Ich bin ziemlich sicher, dass in einem solchen Diagramm der ServiceLocator als "extends oder using di" auftauchen würde.

Weisst du, wenn ich genau drüber nachdenke, habe ich diesen ServiceLocator vermutlich verwendet, bevor Fowler ihn beschrieben hat. Muss so 2002 gewesen sein. Aber ich verstehe jetzt auf was du hinaus willst. Dass der Bohnen-DI-Container von Fowler "ServiceLocator" genannt wird. Aber ist er das wirklich? Benutzt der ServiceLocator auch TypeIds und das Composite Pattern?

Im übrigen nennt Microsoft es auch ServiceContainer. Ich nenne es deshalb DI-Node weil zum Container Aspekt noch die Sache mit dem Compositium aufruft und dieses spezielle Compositum an den PArent delegiert, statt, wie herkömlllcih an das Child.... Was verwirrend hinzukommt, dass ich 2 Implementierungen davon derzeit benutze. Eine einfache, die nur DINode deklariert und eine, die zusätzlich einen ServiceContainer deklariert, um verantwortlichkeiten zu kapseln.

Es macht also wenig sinn, sich zu strikt an theorien zu halten, wenn die theorie besagt dass sie kombiniert und abgewandelt werden möchte. Dazu ist es ja auch geschmackssache. Fowler hat auch nicht die Wahrheit erfundern, beschreibt nur dinge mit seinen Begriffen die andere mit anderen belegt haben. Dass er dabei erfolgreich ist gibt keinem das Recht, hier Wortfaschismus zu betreiben.

Wenn es natürlich so ist, dass du meinst, Fowler hat genau das was ich mache, mit ServiceLocator benannt, macht es natürlich sinn, dass ich den begriff in zukunft übernehme.
 
Falls das so ist, dann wäre mein Tipp an den TE: Check mal das Service Locator Pattern von Fowler. Falls nicht, wurschtel dich durch diese endlosdiskussion hier :D
 
Naja. Du provuzierst recht oft und noch öfter gehst du auf die Schwachstellen meiner Ausführungen "ein" und lässt den Rest aussen vor, dabei willst du oft das falsche verstehen und dich hervortun, indem du behauptest was deiner meinung nach richtig ist, wobei oft nur um begrifflichkeiten gestritten wird. Ich könnte jetzt anfangen, alles mit "dont feed the troll" zu zitieren/kommentieren. Wär vl. gar nicht mal so schlecht.

Aber dieser Eindruck ensteht oft, wenn man alles, wo man zustimmt unkommentiert lässst und stattdessen nur auf das eingeht, was man falsch verstanden hat oder wo man anderer meinung ist. Asche auf mein haupt. Leider gibt es scheins leute, die das aus spass an der freude oder aus ego problemen heraus machen.
 

mrBrown

Super-Moderator
Mitarbeiter
Programmierer A: Ey, ich injecte ein C durch constructor injection in mein B und das mache ich in dem ich von der Klasse namens "Injector" die Factory Funktion "new" verwende.

Programmierer B: Das B-Objekt wird von A mit dem B-Objekt als Konstruktorparameter instanziert.

Was macht mehr sinn? Es gibt bereits grundlegendere Begrifflichkeiten dafür, was hier passiert. Dass das vom Ürinzip her "auch schon" DI ist, ist lediglich ein Auftakt für Fowlers ausführungen. Und dass es wirklich DI ist, stelle ich in frage für alle sprachen, die keine Forwarddeklaration können. (Da gibt es kein "NOINN DAS IST NICHT SO" da gibt es nur ein "verstanden, warum ich das sage?")
Bei Programmierer B hast du was vertauscht (man kann es lesen als 'B wird mit B als Argument instanziert' oder 'A instanziert B und bekommt B als Argument', beides geht nicht), vermutlich sollte das ein "A wird mit einem B als Argument instanziert" sein?

Wie du selbst sagst: Ja, für ua. Fowler wäre beides DI.

Verstanden, was Forward Declaration damit zu tun haben soll, hab ich allerdings nicht. Genausowenig, warum das Einfluss auf DI hat.
Java nutzt man ohne Forward Declaration, du stellst also in Frage, dass es in Java DI gibt? Oder nur, dass ich das A, B, C- Beispiel so in Java implementieren könnte?
Abhängigkeiten existieren dabei ja auch nur in eine Richtung (B hat keine Abhängigkeiten, A nur zu B, C nur zu A un B), man muss nirgends Deklaration von Definition trennen.

Nicht nur für mich fängt DI da an, wo Objekte durch container gekapselt und anhand des Typs identifiziert werden, um sie durch schichten zu schleusen (injecten) die keine Abhängkeit (dependency) zu diesen Typen kennen.
Wie schon gesagt: den Fehler machen viele. Das DI oftmals mit DI-Containern gleichgesetzt wird, ist ein bisschen selbstverschuldet, da man DI nur selten wirklich ohne Container nutzt, möglich ist es aber.
Einfach nur stumpf ein A an ein B übergeben, wenn B ein A braucht, ist bereits DI, völlig ohne Container. Das wirst du auch in jedem Fachbuch und in nahezu jedem Artikel zu dem Thema so finden.

Wenn du meinst, dass das was ich service container nennen eigentlich ein service locataor ist, dann erkläre mir doch bitte, was dann ein service container ist. (Meine Implementierung hat wahrscheinlich aspekte von beidem)
Naja, service container ist eine Klasse von dir, deren Nutzung dem Service-Locator-Pattern entspricht. Ein eigenes Pattern "service container" gibt es nicht, zumindest ist es mir nicht bekannt und auf die schnelle auch nicht zu finden...


Es gab mal ein Bild mit etwa 40 pattern, die mit using/Extends in beziehung gesetzt wurden. Ich hab allerdings keinen Plan, wer dieses geniale Bild in die Welt gesetzt hat und wo es zu finden ist. Das sind für mich pattern, die du kombinieren, implementieren aber niemals (oder sehr selten wie beim observer pattern) (in basisklassen) kapseln kannst. Ich bin ziemlich sicher, dass in einem solchen Diagramm der ServiceLocator als "extends oder using di" auftauchen würde.
Du meinst so eins? http://best-practice-software-engineering.ifs.tuwien.ac.at/patternmap.html

Wie gesagt: ServiceLocator ist keine DI, dazwischen gibt es weder eine "extends"- noch eine "using"-Beziehung.
DI-Container und ServiceLocator haben durchaus Gemeinsamkeiten in der Implementierung, aber genutzt werden sie völlig unterschiedlich. Diese wäre in einem solchen Diagramm aber eher als DI "uses" Service-Locator eingezeichnet, da DI-Container intern das Service-Locator-Pattern nutzen können.

Die uses-Beziehung in obigem Diagramm sind auch keine "muss immer nutzen", sondern ein "kann nutzen", die Besiegung von DI zu Abstract Factory und Container ist also nicht erzwungen. (Sieht man zb auch an "Facade uses Singleton", Facade kann ein Singleton nutzen, muss es aber nicht.)


Dass der Bohnen-DI-Container von Fowler "ServiceLocator" genannt wird. Aber ist er das wirklich?
Nein! eben darauf will ich nicht hinaus! "Bohnen-DI-Container von Fowler" wird nicht Service-Locator gennant. DI (-Container) und Service-Locator werden völlig gegensätzlich genutzt, das ist in dem Artikel ziemlich gut dargestellt.
Und ja, die Unterscheidung ist durchaus wichtig.

(Mit "Bohnen" meinst du Beans? Das wird von Fowler dabei nur in dem Zusammenhang mit einer konkreten DI-Lösung verwendet, die eben als Beispiel für DI-Container und nicht für Service-Locator genutzt wird.)

Benutzt der ServiceLocator auch TypeIds und das Composite Pattern?
Beim Service-Locator kann mann intern nutzen, was man will. Es gibt da keinerlei Einschränkung bei der internen Implementierung, genausowenig bei DI-Containern.

Im übrigen nennt Microsoft es auch ServiceContainer.
ServiceContainer ist die Implementierung einer Registry, die als Service-Locator genutzt werden kann. Es ist aber kein DI-Container und führt auch keine Dependency Injection durch.
Ich weiß nicht wirklich, was du mit diesem Satz in diesem Kontext aussagen willst?

Es macht also wenig sinn, sich zu strikt an theorien zu halten, wenn die theorie besagt dass sie kombiniert und abgewandelt werden möchte. Dazu ist es ja auch geschmackssache. Fowler hat auch nicht die Wahrheit erfundern, beschreibt nur dinge mit seinen Begriffen die andere mit anderen belegt haben. .

Pattern gibt es in der Informatik nicht ohne Grund. Sie dienen auch (und nach manchen vor allem) dazu, Dingen einen Namen zu geben, unter dem jeder das gleiche versteht.
Man kann über Pattern nur reden, wenn man sich "strikt an theorien" hält. Und auch in der Implementierung, auch wenn man kombiniert und abwandelt, ist das Pattern immer eindeutig erkennbar. Wenn ein Muster nicht erkennbar ist, ist auch keins vorhanden - und ebenso: ist ein Muster erkennbar, ist es auch vorhanden.

Über Pattern reden, wenn jeder da etwas anderes drunter versteht, klappt nicht, sieht man ja gut an dieser Unterhaltung: ich versteh unter DI das Übergeben von Abhängigkeiten, du deine selbstentwickelte Lösung.

Es ist also nicht Geschmacksache, was man darunter versteht, sondern eine erste Definition ist Grundlage dafür, dass man es überhaupt nutzen und drüber reden kann.

Wenn es natürlich so ist, dass du meinst, Fowler hat genau das was ich mache, mit ServiceLocator benannt, macht es natürlich sinn, dass ich den begriff in zukunft übernehme.

Ja, das was du machst, ist Anwendung des Service-Locator-Patterns. Und Service-Locator ist etwas anderes als DI. Es kann in der Implementierung von Service-Locator und DI-Container Gemeinsamkeiten geben (DI-Container nutzen so intern durchaus Service-Locators), aber die Benutzung ist völlig Gegensätzlich.

Die Benennung als Service-Locator gab's übrigens auch vorher Fowlers Artikel schon, das stammt aus den Anfangstagen von JavaEE)
 

X5-599

Top Contributor
Also ich hab das alles mal überflogen. Die verschiedenen Begrifflichkeiten hatte ich ja anfangs auch miteinander verwechselt. Da bin ich jetzt ein bisschen schlauer. Danke dafür. Aber vermutlich hätte ich besser mit konkreten Beispielen anfangen sollen; Sorry, mein Fehler.

Genaugenommen arbeite ich an einem Projekt: ServiceLayer -> DAO Layer -> Datenbank

Tatsächlich sind die Serviceklassen gar nicht so das Problem. Eher die DAO Klassen. Genauer gesagt die Hibernate Implementierungen dieser. Denn die sollen als Konstruktor Parameter Hibernates SessionFactory bekommen. Und soweit ich das verstehe soll dieses spezielle Objekt nur einmal gebaut werden und dann an alle Abhängigen Klassen verteilt werden.

Das habe ich nun mir einer Factory gelöst. Die kann per statischem Zugriff benutzt werden. Die Implementierung der Factory hat als Dependency ein einmalig erzeugtes SessionFactory Objekt welches für die Instanziierung der einzelnen DAOs benutzt wird.

Nutzung ohne Factory sähe so aus:
Code:
SessionFactory sessionFactory = new Configuration().configure("hibernate.cfg.xml").buildSessionFactory();
EmployeeDao eDao = new EmployeeDaoHibernate(sessionFactory);
EmployeeService eService = new EmployeeServiceImpl(eDao);

So ließen sich meine Services erzeugen, überall da wo sie als Dependency injiziert werden sollen. zb. new HRController(eService).

Mit Factory dann so:
Code:
DaoFactory hibernateFactory = DaoFactory.getDefaultFactory();
EmployeeDao eDao = hibernateFactory.createEmployeeDao();
EmployeeService eService = new EmployeeServiceImpl(eDao);

Ich bin zu dem Schluss gekommen, dass eine Factory für DAOs die Anforderung der nur einmalig zu erzeugenden SessionFactory recht elegant löst. Zu dem kann ich auch leicht auf zB EclipseLink wechseln.

Der relevante Teil der abstrakten Factory sieht so aus:
Code:
public abstract EmployeeDao createEmployeeDao();

public static DaoFactory createFactory(ORMProvider variant)
{
	variant = Objects.requireNonNull(variant, "ORMProvider cannot be null!");
	
	DaoFactory daoFactory = null;
	
	switch(variant)
	{
		default:
			throw new RuntimeException("Chosen ORMProvider is not implemented yet.");
			
		case ECLIPSE_LINK:
			daoFactory = new EclipseLinkDaoFactory();
			break;
			
		case HIBERNATE:
			// create the SessionFactory from hibernate.cfg.xml
			SessionFactory sessionFactory = new Configuration().configure("hibernate.cfg.xml").buildSessionFactory();
			daoFactory = new HibernateDaoFactory(sessionFactory);
			break;
	}
	
	return daoFactory;
}
 

mrBrown

Super-Moderator
Mitarbeiter
Ich weiß nicht ob das schon gefragt wurde, aber wenn du mit Hibernate zugange bist, passiert das zufällig im JavaEE/Spring/etc-Kontext?


Tatsächlich sind die Serviceklassen gar nicht so das Problem. Eher die DAO Klassen.
In zumindest meinen obigen Texten mein Service generell alle Objekte, die Dinge bereitstellen - also sowohl deine Services, als auch die DAOs ;) Terminologie ist leider dabei etwas verwirrend...


Das habe ich nun mir einer Factory gelöst. Die kann per statischem Zugriff benutzt werden. Die Implementierung der Factory hat als Dependency ein einmalig erzeugtes SessionFactory Objekt welches für die Instanziierung der einzelnen DAOs benutzt wird.
Ja, das ist durchaus eine passende Lösung dafür (über das static dabei kann man streiten, deine Verwendung ist aber die der wenigen, wo zumindest ich es ok fände, weil das statische nicht in die eigentliche Anwendung "leakt".)

Ist gleichzeitig auch DI (halt ohne Container), die deine Services die nötigen Abhängigkeiten bekommen, und selber von der "Infratstuktur" unabhängig sind.

Wenn mal zu einem großen CI-Container gewechselt wird, kann man den Großteil sogar einfach übernehmen, nur die "Glue-Code" kann dann weg.

Zu dem kann ich auch leicht auf zB EclipseLink wechseln.
Wenn das so gekapselt ist, gibts da auch durchaus noch andere interessante Wege zum wählen des Providers, zB automatisch immer den nehmen, der im Classpath verfügbar ist.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
nrg Wie würdet ihr eine "Dauerschnittstelle" implementieren? Allgemeine Java-Themen 5
M Wie würdet ihr Dokumente aus Java realisieren? Allgemeine Java-Themen 4
B Was würdet ihr dafür berechnen? Allgemeine Java-Themen 7
G Welches Java GUI Buch würdet Ihr empfehlen Allgemeine Java-Themen 2
J Wie würdet Ihr Daten 1 Jahres abbilden Allgemeine Java-Themen 2
izoards JAR als Windows Service mit Appache Procrun (prunsrv) Allgemeine Java-Themen 6
A Zweite Service Klasse beim Kompilieren Allgemeine Java-Themen 6
O Service oder Controller Allgemeine Java-Themen 6
OnDemand Thread / Service abbrechen Allgemeine Java-Themen 3
H Aufruf eines Web Service anhand übergebenen Parameter Allgemeine Java-Themen 2
K Multithreading: Service(Task), wait und continue Allgemeine Java-Themen 21
X Threads Java Chached Executors Service Allgemeine Java-Themen 12
P Entity Objekt Methoden vs Service methoden Allgemeine Java-Themen 2
K Hilfe bei GUI für Pizza-Service Allgemeine Java-Themen 11
L TV Programm API/Web Service o.ä. Allgemeine Java-Themen 6
D Java Objekt als Service in Runtime registrieren Allgemeine Java-Themen 1
Nero90 FileSystem Watcher Service Allgemeine Java-Themen 1
W Windows (Service) Hooking Allgemeine Java-Themen 8
C Threads ExecutorService shutdown abbrechen und service "starten" ? Allgemeine Java-Themen 3
A Framework für einen Web Service Allgemeine Java-Themen 6
M Webservices: WSDL Files ohne "Service" Element? Allgemeine Java-Themen 4
D ewig laufendes Javaprogramm ("Service") Allgemeine Java-Themen 17
D Executor Service nach getaner Arbeit beenden Allgemeine Java-Themen 3
Iron Monkey Listening for Print Service Status Changes Allgemeine Java-Themen 2
D Daemon bzw. Windows Service Allgemeine Java-Themen 5
O Unterschied zwischen ThreadPoolExecutor und Executor Service Allgemeine Java-Themen 7
J url-Service timeout einrichten? Allgemeine Java-Themen 10
G Java App als Service Allgemeine Java-Themen 2
N C source to Java Source -> compile java layer? Allgemeine Java-Themen 9
K layer in Jsp Aktualisieren Allgemeine Java-Themen 3

Ähnliche Java Themen

Neue Themen


Oben