Datenbankzugriffsschicht ohne mit Singletons um sich zu schmeißen?
-
Mal noch ne andere Frage. Was soll das eigentlich beim Testen bringen, wenn die DB-Klasse kein Singleton ist? Die DB ansich ist ja sowieso global, also alles was ich in die DB schreibe steht auch im nächsten Testdurchlauf wieder drin, egal ob Singleton oder nicht.
-
aaaaaaaaaüö schrieb:
Die DB ansich ist ja sowieso global, also alles was ich in die DB schreibe steht auch im nächsten Testdurchlauf wieder drin, egal ob Singleton oder nicht.
Ähm nein, du kannst z.B. Ein Mock Objekt statt einer richtigen Datenbank übergeben!?
-
@aaaaaaaaaüö:
Wie willst du z.B. zwei Instanzen eines "Service" im gleichen Prozess laufen lassen, die unterschiedliche Datenbanken verwenden (weil es Instanzen für verschiedene Kunden sind, oder ein Testsystem + ein Stagingsystem etc.), wenn die DB-Connections von einem Singleton verwaltet werden?
-
Eisflamme schrieb:
Ich kenne mich jetzt nicht so besonders damit aus. Aber wird DI hier jetzt als Lösung für DB dargestellt oder als allgemeine Lösung für alles Mögliche?
DI ist eine Lösung für alles Mögliche, auch für deine Datenbank.
-
aaaaaaaaaüö schrieb:
Mal noch ne andere Frage. Was soll das eigentlich beim Testen bringen, wenn die DB-Klasse kein Singleton ist? Die DB ansich ist ja sowieso global, also alles was ich in die DB schreibe steht auch im nächsten Testdurchlauf wieder drin, egal ob Singleton oder nicht.
Abgesehen von Mocking kannst du natürlich die Test-Datenbank vor jedem Testdurchlauf (oder vor jedem Test) auch auf einen Ursprungszustand zurücksetzen.
MfG SideWinder
-
hustbaer schrieb:
@aaaaaaaaaüö:
Wie willst du z.B. zwei Instanzen eines "Service" im gleichen Prozess laufen lassen, die unterschiedliche Datenbanken verwenden (weil es Instanzen für verschiedene Kunden sind, oder ein Testsystem + ein Stagingsystem etc.), wenn die DB-Connections von einem Singleton verwaltet werden?Ich weiß, dass ich mit einem Singleton nicht alles machen kann, aber ich seh überhaupt keinen Vorteil in diesem einmal Erstellen und dann herumreichen, wie es dot erklärt hat, vielleicht hat er es auch falsch erklärt und das hat nichts mit DI zu tun oder ich hab es falsch verstanden oder ich habs verstanden und finde DI schlecht.
Nehmen wir mal an es gibt ein fertiges System das Userdaten (Name, Kontonr.) und alle möglichen anderen Daten in einer DB speichert. Jetzt soll das System aus Sicherheitsgründen so umgebaut werden, dass die Kontonr. in einer anderen Datenbanken gespeichert wird, der Rest kann in der alten DB bleiben. Wenn ich ein Singleton habe kann ich relativ einfach daraus eine Factory mit einem Parameter machen. Der Compiler sagt mir dann wo ich hinschauen muss und ich muss nur den Parameter bei der Singleton/Factroy Verwendung angeben. Wenn ich die DB jetzt immer als Parameter bei Konstruktoren angegeben hab, muss ich jetzt überall da, wo auf die Kontonr. zugegriffen wird, einen zweiten Parameter für die andere DB angeben. Ist das nicht viel hässlicher? Vorallem, gibt es beim herrumreichen, doch auch noch jede Menge "Durchschleifklassen", also Klassen die die DB eigentlich garnicht brauchen, sondern nur an eine andere weitergeben?
-
aaaaaaaaaüö schrieb:
Wenn ich ein Singleton habe kann ich relativ einfach daraus eine Factory mit einem Parameter machen.
D.h. anstatt eine Datenbank übergeben zu bekommen erzeugt sich einfach jeder der eine brauch eine?
aaaaaaaaaüö schrieb:
Wenn ich die DB jetzt immer als Parameter bei Konstruktoren angegeben hab, muss ich jetzt überall da, wo auf die Kontonr. zugegriffen wird, einen zweiten Parameter für die andere DB angeben.
Oder noch besser: Du kapselst das alles in einem Objekt das sich darum kümmert was genau wie wohin gespeichert werden soll. Dann muss nur dieses Objekt die beiden Datenbanken kennen und der restliche Code ist davon unabhängig und bekommt nicht mit ob es jetzt 1, 2 oder 3 Datenbanken gibt oder ob vielleicht irgendwas dann auch noch wo anders gespeichert werden soll.
aaaaaaaaaüö schrieb:
Ist das nicht viel hässlicher?
Nein. Singleton wäre hässlich weil es diese Abhängigkeit verschleiert. Aber nur weil du sie nicht siehst bedeutet das nicht dass sie nicht da ist.
aaaaaaaaaüö schrieb:
Vorallem, gibt es beim herrumreichen, doch auch noch jede Menge "Durchschleifklassen", also Klassen die die DB eigentlich garnicht brauchen, sondern nur an eine andere weitergeben?
Nein gibt es nicht, wenn du solche Klassen hast dann machst du grad was falsch.
-
dot schrieb:
aaaaaaaaaüö schrieb:
Wenn ich ein Singleton habe kann ich relativ einfach daraus eine Factory mit einem Parameter machen.
D.h. anstatt eine Datenbank übergeben zu bekommen erzeugt sich einfach jeder der eine brauch eine?
Ne, er bekommt die die er anfordert.
aaaaaaaaaüö schrieb:
Wenn ich die DB jetzt immer als Parameter bei Konstruktoren angegeben hab, muss ich jetzt überall da, wo auf die Kontonr. zugegriffen wird, einen zweiten Parameter für die andere DB angeben.
Oder noch besser: Du kapselst das alles in einem Objekt das sich darum kümmert was genau wie wohin gespeichert werden soll. Dann muss nur dieses Objekt die beiden Datenbanken kennen und der restliche Code ist davon unabhängig und bekommt nicht mit ob es jetzt 1, 2 oder 3 Datenbanken gibt oder ob vielleicht irgendwas dann auch noch wo anders gespeichert werden soll.
Irgendwie hört sich das immer mehr nach einem ManagerManager an.
aaaaaaaaaüö schrieb:
Ist das nicht viel hässlicher?
Nein. Singleton wäre hässlich weil es diese Abhängigkeit verschleiert. Aber nur weil du sie nicht siehst bedeutet das nicht dass sie nicht da ist.
aaaaaaaaaüö schrieb:
Vorallem, gibt es beim herrumreichen, doch auch noch jede Menge "Durchschleifklassen", also Klassen die die DB eigentlich garnicht brauchen, sondern nur an eine andere weitergeben?
Nein gibt es nicht, wenn du solche Klassen hast dann machst du grad was falsch.
Hast du mal ein großes Open Source Projekt zum anschauen das so aufgebaut ist, wie du das sagst?
-
aaaaaaaaaüö schrieb:
Irgendwie hört sich das immer mehr nach einem ManagerManager an.
Wie auch immer du jetzt darauf kommst...
aaaaaaaaaüö schrieb:
Hast du mal ein großes Open Source Projekt zum anschauen das so aufgebaut ist, wie du das sagst?
Ich hab mir noch nie den Code von nem großen Open Source Projekt angetan. Also leider nicht...
-
aaaaaaaaaüö schrieb:
hustbaer schrieb:
@aaaaaaaaaüö:
Wie willst du z.B. zwei Instanzen eines "Service" im gleichen Prozess laufen lassen, die unterschiedliche Datenbanken verwenden (weil es Instanzen für verschiedene Kunden sind, oder ein Testsystem + ein Stagingsystem etc.), wenn die DB-Connections von einem Singleton verwaltet werden?Ich weiß, dass ich mit einem Singleton nicht alles machen kann, aber ich seh überhaupt keinen Vorteil in diesem einmal Erstellen und dann herumreichen, wie es dot erklärt hat, vielleicht hat er es auch falsch erklärt und das hat nichts mit DI zu tun oder ich hab es falsch verstanden oder ich habs verstanden und finde DI schlecht.
Nehmen wir mal an es gibt ein fertiges System das Userdaten (Name, Kontonr.) und alle möglichen anderen Daten in einer DB speichert. Jetzt soll das System aus Sicherheitsgründen so umgebaut werden, dass die Kontonr. in einer anderen Datenbanken gespeichert wird, der Rest kann in der alten DB bleiben. (...)
Ich wollte mit dem Beispiel versuchen dir klarzumachen, von welchen "es könnte mehrere Datenbanken geben" Fällen wir sprechen (oder zumindest ich spreche).
Was du beschreibst, wird durch DI/rumreichen/wie-auch-immer-man-es-nennen-will weder einfacher noch schwerer.
Was ich meine dagegen schon.
-
Wie macht ihr das mit einem Logger? Macht ihr ein Singleton oder gebt ihr den an praktisch jede Klasse weiter?
-
Logger... schrieb:
Wie macht ihr das mit einem Logger? Macht ihr ein Singleton oder gebt ihr den an praktisch jede Klasse weiter?
Falls Du Debug-Logger meinst, nicht weitergeben.
Singleton oder nicht? Die Frage stellt sich nicht wirklich, da per Makro geloggt wird, zum Beispiel#define LOG(...) do{std::ofstream("log.txt",ios::app)<<__VA_ARGS__;}while(false)
Das kann jederzeit so leicht umgestellt werden von so auf globale Variable oder auf Singleton, daß man eigentlich keine Fehlentscheidung treffen kann.
-
Was bring do...while(false); ?
-
Und was machst du in Sprachen die keine Makros haben, z.b. Java?
-
Logger... schrieb:
Was bring do...while(false); ?
Schiebt das ganze in einen Block, verhindert bspw. das Loggen an "unüblichen" Bereichen wo das Makro schaden anrichten könnte.
@Java: Dort würde man eine fertige Bibliothek nehmen. Da gibt es sogar zwischen den Bibliotheken eine Quasi-Standardisierung indem das SLF4J-Interface implementiert wird: http://www.slf4j.org/ Dort funktioniert das über eine LoggerFactory die afaik ein Singleton ist.
MfG SideWinder
-
volkard schrieb:
Die Frage stellt sich nicht wirklich, da per Makro geloggt wird, zum Beispiel
#define LOG(...) do{std::ofstream("log.txt",ios::app)<<__VA_ARGS__;}while(false)
ich hoffe das war jetzt beispielcode und ihr loggt nicht so in Produktivanwendungen
-
SideWinder schrieb:
Logger... schrieb:
Was bring do...while(false); ?
Schiebt das ganze in einen Block, verhindert bspw. das Loggen an "unüblichen" Bereichen wo das Makro schaden anrichten könnte.
Reicht da nicht {...} ?
-
Das würde wahrscheinlich reichen, wenn du kein Semikolon hinter den Makroaufruf setzt. Sonst bekommst du Probleme:
if(irgendwas) LOG("was auch immer"); else machWas();
Wenn du lediglich nen Block ohne Schleife in LOG hast, mutiert das Semikolon zu ner leeren Anweisung und das else gehört nicht mehr zum if.
-
BierzeltOmi schrieb:
volkard schrieb:
Die Frage stellt sich nicht wirklich, da per Makro geloggt wird, zum Beispiel
#define LOG(...) do{std::ofstream("log.txt",ios::app)<<__VA_ARGS__;}while(false)
ich hoffe das war jetzt beispielcode und ihr loggt nicht so in Produktivanwendungen
Es ist Beispielcode.
Aber welches Problem hast Du damit?
-
Auch wenn Makros im Allgemeinen eine schlechte Idee sind, für Logging sind sie praktisch, es gibt keinen andren Weg automatisch Dinge wie Datei + Zeilennummer mitzuloggen
Wobei ich mein Log auch oft per DI übergeb. Man braucht das Ding dann doch auch nur an wenigen Stellen.