Codedesign - "Globale" Klassen

The Ripper

Lt. Commander
Registriert
Juni 2012
Beiträge
1.969
Hallo,

ich wollte mich mal informieren wie andere Personen folgendes Problem lösen. Man nehme an, man hätte einen Logger, den man eigentlich fast über den kompletten programmspezifischen Code braucht, eigentlich logisch. Gut, dabei bleibt es aber nicht: Konfigurationen abrufen und speichern will man natürlich auch ... möglichst überall? Eventuell noch weitere solche Kandidaten...

Folgende Lösungsmöglichkeiten wären mir jetzt eingefallen wie man das lösen könnte:

- klassische globale Variable
- Singleton
- Dependance Injektion: (1) Jedes einzelne Modul einzeln oder (2) die Klassen in einer Sammelklasse unterbringen?
- ??

Finde jetzt alle Möglichkeiten nicht unbedingt perfekt u. vollständig zufriedenstellend. Wie würdet ihr das lösen? Mit Berücksichtigung von Codelesbarkeit, klare Struktur und effizienter Ressourcennutzung?
 
Zuletzt bearbeitet:
Bei einer Config Klasse würde ich ein Singleton nehmen, bei einem Logger aber zwingend eine komplett statische Methode die ich a la "Logger.Warning (10, "lp0 on fire!");" schreiben kann. So eine Logausgabe muss zwingend auf eine einzige Zeilge passen sonst müllt das den Code zu sehr voll.
 
Die eine Zeile für den Logger bekommt man auch für die anderen Varianten hin, man muss nur evtl. etwas mehr Initialisieren und das kann man auch in den Hintergrund auslagern. Fürs Logging würd ich eh fertige Lösungen einsetzen, die haben dann meist auch ein "best Practise" wie man sie einsetzt (besonders cool find ich an der Stelle Ansätze mit Aspekt-orientierter Programmierung)

Der Vorteil von DI ist halt das man die Klassen besser Unit-testen kann weil man die Abhängigen Module einfach austauschen kann. Für ein kleines Hobby-Projekt vielleicht nicht so wichtig, da kann man sich den Aufwand sparen und einfach Singletons oder statische Klassen nehmen. Sobald es größer wird sieht es aber anders aus und ich würd nicht drauf verzichten. Den absoluten Königsweg wie man es aber am besten implementiert such ich auch noch ;-)
 
Bei der statischen Methode wäre ich ziemlich unflexibel was Austauschbarkeit und Individualität des Logger angeht, denke ich: So kann ich mit in Klassen gekapselten Loggern statt diesen Logger auch jenen übergeben oder einfach noch zusätzlich einen Logger anhängen (Verkettung). Vor allem in Projekten, die gemeinsam bearbeitet werden notwendig mMn. Einzeiler werden dadurch nicht wirklich verhindert, selbst bei Dependency Injektion (2). Wieso auch?

Code:
Claas foo
{
   private Logger log;
   foo(int a, int b, LoggerInterface Abc)
   {
      log = Abc;
   }
   doStuff
   {
      ...
      log.log(error, "Fehler aufgetreten")
      ...
   }
Kannst du den Singleton auch begründen und eventuell gegenüberstellen?
 
Zuletzt bearbeitet:
Ein Logger darf für den Aufruf nur 1 Zeile brauchen, keine Var Deklaration, nix. Am besten wäre schon das "include <logger>" wegzubekommen, aber das geht kaum. Der Logger muss ich üebrall möglichst schnell und leicht reinschreiben können, praktisch ein Debug Statement.

Eine Config Klasse ist weniger universell, wird viel seltener gebraucht im Code, aber ein Singleton weil es eben nur eine Config für das Programm geben kann. Da ist es auch ok, wenn ich erst ne Var deklarieren muss über die ich dann meine Config Daten anspreche.
 
Der Singleton unterscheidet sich von der DI ja nur dadurch das man sich selbst aktiv diem Instanz holt und nicht von außen übergeben bekommt. Ist aber halt ähnlich unflexibel wie eine statische Lösung.


Aktuell würd ich eine DI Lösung favorisieren bei der man nicht alle Klassen einzeln bekommt sondern einen Manager der einen die Klasse geben kann. Bin mir aber wie gesagt nicht sicher ob das wirklich die beste Lösung wäre. Aber es würde den Aufwand reduzieren wenn recht viele Klassen per DI übergeben werden müssten.
 
Ich hab hier nen Logger, da rufe ich letztenendes auch nur statische Methoden auf, ausgeführt werden dann letztenendes aber programmdefinierte Callbacks. Das gibt mir zwar nicht die Möglichkeit, einzelne Teile des Programms mit unterschiedlichen Loggern auszustatten, aber man kann mit den Log-Messages im Grunde machen, was man will.

Ist letztenendes aber auch eine Frage der Anforderung. DI ist immer die flexibelste Lösung, hat aber den in so einem Fall signifikanten Nachteil, dass man jede Klasse, die entweder direkt den Logger nutzt, oder aber andere Klassen instantiiert, die (direkt oder indirekt) den Logger brauchen, mit nem entsprechenden Pointer versorgen muss. Und das können eine ganze Menge Klassen werden, auch wenn diese aus funktionaler Sicht gar nichts mit dem Logger zu tun haben.
 
Zuletzt bearbeitet:
Wieso darf es bei der Instanziierung vom ganzen Objekt nicht einmalig ne Zuweisung/Deklaration geben? Was ist mit den Nachteilen, die du hinnehmen müsstest?
Ergänzung ()

DI ist immer die flexibelste Lösung, hat aber den in so einem Fall signifikanten Nachteil, dass man jede Klasse, die entweder direkt den Logger nutzt, oder aber andere Klassen instantiiert, die (direkt oder indirekt) den Logger brauchen, mit nem entsprechenden Pointer versorgen muss. Und das können eine ganze Menge Klassen werden, auch wenn diese aus funktionaler Sicht gar nichts mit dem Logger zu tun haben.
Genau aus dieser Situation heraus habe ich den Thread erstellt.

Ich tendieren atm zur Manager-Lösung, die Flexibilität von DI ist mir dabei ziemlich wichtig. Was haltet ihr von der Lösung? Gibt's da nicht noch andere Lösungsansätze in diese Richtung?
 
Logger werden doch fast ausschließlich als statische, fest verdrahtete Membervariablen verwendet. Trotzdem sind sie flexibel, da sie auf alle mögliche Art und Weise frei konfigurierbar sind. Nicht nur per Konfigdatei, sondern auch dynamisch zur Laufzeit. Logging ist sozusagen ein Beispiel für eine pragmatische Entscheidung gegen DI.

Zum Thema Dependency Injection. Es nicht damit getan, ein paar Membervariablen per Annotation oder über den Constructor oder Properties von außen zu hereinzugeben. Worauf man achten muss sind fest kodierte Abhängigkeiten in Methoden:
- Objektinstanziierungen mit new
- Verwenden von statischen Methoden, wie z.B. Singleton-Instanz-Methoden

Beide Abhängigkeiten können durch DI ersetzt werden. Den Vorteil der losen Kopplung und des dadurch leichter anpassbaren Codes erkauft man sich aber durch steigende Komplexität und schlechtere Lesbarkeit, also ist das nicht immer sinnvoll.
Punkt zwei ist der Grund, warum das Singleton-Pattern als Antipattern bezeichnet wird. Hier lohnt sich DI vielleicht am ehesten.
Und dann muss es natürlich noch den schmutzigen Code geben, der alles zu einer Anwendung zusammensteckt und dabei mit new und Zugriffen auf statische Methoden nur so um sich schmeißt.
 
  • Gefällt mir
Reaktionen: new Account()
Zurück
Oben