Datenbankzugriffsschicht ohne mit Singletons um sich zu schmeißen?
-
Das "ver" von "verstecke" habe ich gar nicht gesagt.
-
volkard schrieb:
Das "ver" von "verstecke" habe ich gar nicht gesagt.
Irgendwie vermutete ich unterbewusst, dass das ein Grund dagegen sein könnte. Ich glaube aber weiterhin, dass ich gar keine Logik in die Konfigurationsdatei stecke, dementsprechend also auch nichts verstecke.
MfG SideWinder
-
dot schrieb:
fdfdg schrieb:
Magst du mal ein konkretes Beispiel geben, wie so ein Dependency Injection Logger aussehen könnte?
class Log { private: Log(const Log&); Log& operator =(const Log&); protected: Log() {} ~Log() {} public: virtual void message(const std::string& msg) = 0; virtual void warning(const std::string& msg, int level) = 0; virtual void error(const std::string& msg, int level) = 0; };
Kann es sein, dass du Dependency Injection mit Interfaces verwechselst, dass Beispiel bringt mal garnichts.
-
Mach doch mal ein Beispiel, wo Klasse A in ein Logfile schreibt, Klasse B in ein Logfile und das Logwindow schreibt und Funktion C in ein Logfile und auf Console loggt.
-
DI wurde doch schon ausführlich diskutiert. Jedes Objekt das was loggen will bekommt nun eben so ein Interface!? Das Objekt welches ich übergeb kann nun in ein Logfile oder ein Logwindow oder was auch immer schreiben...
-
Mach doch mal das Beispiel von oben.
-
Was genau ist daran jetzt bitte noch unklar!?
-
Machst du sowas?
class KlasseB { public: KlasseB(Log fileLogger, Log windowLogger)... }
oder
class KlasseB { public: KlasseB(Log fileAndWindowLogger)... }
-
Ich denke auch, dass man Singletons nicht für DB-Verbindungen nutzen sollte. Ich hab hier eine historisch gewachsene Software bei der die Instanz der DB-Verbindung immer von der obersten Ebene als Parameter an die nächst tiefere reingereicht wird. Es gab immer nur eine Instanz der DB-Verbindung und die änderte sich eigentlich auch nicht. Hab damals überlegt, ob man die Verbindung auch in einem Singleton unterbringen und in den entsprechenden Funktionen abfragen könnte. Bloß gut, dass wir das nicht gemacht haben.
Zwei Jahre später kam nämlich heraus, dass unter bestimmten Umständen (und an ganz bestimmten Stellen) eine andere DB-verbindung (mit anderem Zeichensatz) zur selben DB benötigt wird. Die können wir ganz bequem an den entsprechenden Stellen reinreichen und alles Funktioniert wie bisher. Bei der singleton-Variante hätten wir erst den Code und die möglichen Seiteneffekte analysieren müssen.
Mir persönlich gefällt das Reinreichen der Instanz in jede Funktion aber auch nicht.
ähm schrieb:
Machst du sowas?
class KlasseB { public: KlasseB(Log fileLogger, Log windowLogger)... }
oder
...Das würde mich auch mal interessieren. Kann ja nicht schaden mal eine Alternative zu sehen.
-
dot schrieb:
BierzeltOmi schrieb:
Thread-Sicherheit?
Dependency Injection
Quatsch. Nur weil du die Klasse übergibst ändert das nichts. Du musst immer noch locken vor du von verschiedenen Threads ins gleiche Log-File schreibst.
-
yxcvbnm schrieb:
dot schrieb:
BierzeltOmi schrieb:
Thread-Sicherheit?
Dependency Injection
Quatsch. Nur weil du die Klasse übergibst ändert das nichts. Du musst immer noch locken vor du von verschiedenen Threads ins gleiche Log-File schreibst.
Das musst du aber in jedem Fall, daher ging ich davon aus dass BierzeltOmi das nicht gemeint haben kann denn das wäre ja sinnlos. Bei der DI Variante ist zumidest immer klar definiert wer wann welches Log verwendet...
-
ähm schrieb:
Machst du sowas?
Nein ich mach sowas:
class KlasseB { public: KlasseB(Log& log, ...) ... }
Was genau für eine Art von Log ich übergeb ist für KlasseB irrelevant.
-
Ok und das nennt sich schon Dependency Injection? Ich hatte mir etwas kniffligeres vorgestellt, aber gut..
-
@dot: Findest du constructor-injection gut weil du es hier dauernd praktizierst?
Und vielleicht sollten wir für C++ nicht solcherlei Java-Beispiele bringen, da das dort ohnehin nicht state-of-the-art ist wie volkard uns bereits mitgeteilt hat.
MfG SideWinder
-
SideWinder schrieb:
@dot: Findest du constructor-injection gut weil du es hier dauernd praktizierst?
Und vielleicht sollten wir für C++ nicht solcherlei Java-Beispiele bringen, da das dort ohnehin nicht state-of-the-art ist wie volkard uns bereits mitgeteilt hat.
MfG SideWinder
Okay, wie sieht denn dann das typische state-of-the-art c++ Beispiel aus?
-
Dependency Injection im Constructor bringt zwar ein paar Vorteile gegenüber einem Singleton, aber braucht auch mehr Speicher und Performance, wenn man z.B. 1000000 Objekte erstellt und denen allen einen Logger zuweist.
-
SideWinder schrieb:
@dot: Findest du constructor-injection gut weil du es hier dauernd praktizierst?
Was gäbe es denn für Alternativen in C++?
bewertung schrieb:
Dependency Injection im Constructor bringt zwar ein paar Vorteile gegenüber einem Singleton, aber braucht auch mehr Speicher und Performance, wenn man z.B. 1000000 Objekte erstellt und denen allen einen Logger zuweist.
Der Zugriff auf einen Singleton über die getInstance() Methode ist auch kein Leichtgewicht. Und wenn du 100000 Objekte hast die alle auf einen anderen Logger loggen können müssen hast du sowieso ganz andere Probleme...
-
dot schrieb:
SideWinder schrieb:
@dot: Findest du constructor-injection gut weil du es hier dauernd praktizierst?
Was gäbe es denn für Alternativen in C++?
* Setter
* Thread-Locals
-
hustbaer schrieb:
* Setter
Damit ändert sich doch am Prinzip nix!?
hustbaer schrieb:
* Thread-Locals
Das hätte doch eine vollkommen andere Semantik. Das hilft mir doch nur wenn ich die Dependency eben an einen bestimmten Thread binden will und nicht an ein bestimmtes Objekt!? Ich würde das jetzt nicht als Alternative sehen sondern als was völlig Orthogonales.
Aber die Idee das Logging nicht auf einer per-Komponenten- sondern einer per-Thread-Basis zu machen ist sehr interessant und unter Umständen wirklich sehr elegant
, werd ich mir auf jeden Fall merken
-
dot schrieb:
hustbaer schrieb:
* Thread-Locals
Das hätte doch eine vollkommen andere Semantik. Das hilft mir doch nur wenn ich die Dependency eben an einen bestimmten Thread binden will und nicht an ein bestimmtes Objekt!? Ich würde das jetzt nicht als Alternative sehen sondern als was völlig Orthogonales.
Naja...
Sagen wir mal so...
Thread-Locals sind ein möglicher Weg, kontextbezogene Lookups zu machen.
Und kontextbezogene Lookups kann man wiederum verwenden um Inversion of Control zu machen.
Und Inversion of Control ist schon eng verwandt mit Dependency Injection.Nochmal dazu:
Das hilft mir doch nur wenn ich die Dependency eben an einen bestimmten Thread binden will und nicht an ein bestimmtes Objekt!?
Es reicht ja oft (meistens?), dass man Dependencies an einen "Task" ("Request", "Job") binden kann.
Wenn das Programm so strukturiert ist, dass es, während der Lebenszeit eines Tasks, eine 1:1 Beziehung Task:Thread gibt, dann reicht es, z.B. einen Service Locator an einen Thread zu binden.
Wenn es so eine 1:1 Beziehung nicht gibt wird es etwas komplizierter. Lässt sich aber auch noch machen, man muss dann halt an allen Stellen wo ein Thread anfängt/aufhört für einen Task tätig zu werden die Thread-Local Variable entsprechend anpassen. (Kann man z.B. ohne grossen Aufwand machen, indem man alle Callbacks/Thread-Funktionen in einen Hilf-Funktor einwickelt.)
Alternativ kann man natürlich den Service Locator bzw. den Task überall als Parameter rumreichen.