Warum Singletons bööse sind

Ich schätze mal, ich bin nicht der einzige, der von den 23 GoF-Patterns das Singleton-Pattern als erstes kennen gelernt hat. Aber woran liegt das? Vielleicht, weil es einfach ist? Und bequem? Und natürlich weil man es wunderbar dazu verwenden kann, sich um richtige OO herum zu drücken…

Das Singleton – ein Anti-Pattern.

Mittlerweile halte ich das Singleton-Pattern für ein Antipattern. Es mag vielleicht ein paar ganz seltene Fälle geben, in denen es u.U. sinnvoll sein könnte, oft ist es aber einfach nur… problematisch. Das hat mehrere Gründe:

  • Es verleitet dazu, objektorientierte Grundsätze über Bord zu werfen und wieder prozedural zu programmieren.
  • Es verschleiert Abhängigkeiten zu der Klasse (man muss schon in den Code gucken um zu sehen, ob eine Klasse das Singleton benutzt) und erhöht die Kopplung, was Wiederverwendbarkeit und Übersichtlichkeit einschränkt.
  • Singletons verletzen das Single Responsibility Principle. Eine Klasse soll nur für eine klar definierte Aufgabe zuständig sein. Ein Singleton hat aber mindestens schonmal zwei Aufgaben. Nämlich neben der eigentlichen Aufgabe muss es noch sicherstellen, dass es kein zweites von seiner Sorte gibt.
  • Es erschwert das Testen, weil es einen globalen Zustand einführt und man nur schwer Dummies dafür schreiben kann.
  • Es führt (unnötige) Beschränkungen ein. Wenn in einer späteren Programmversion nun doch mehr als eine Instanz von Nöten ist, muss das Singleton mühsam entfernt werden.
  • Ein Singleton ist nur in sequentiellen Programmen einfach zu implementieren. Bei nebenläufigen oder gar verteilten Programmen ist es eine Herausforderung. Auch in Verbindung mit DLLs kann es zu Problemen kommen. Dazu kommt noch, dass, wenn man bei der Implementierung einen Fehler gemacht hat, man den Fehler oft erstmal gar nicht sieht.
  • Will man eine Klasse von einem Singleton ableiten, wird man ebenfalls aus lustige Probleme stoßen. Und, wenn man selbst nicht ableitet, will das vielleicht jemand anders tun. Dann hat der die Probleme. Man könnte jetzt natürlich sagen, dann macht man die Klasse eben final, aber erstens unterstützt das nicht jede Sprache und zweitens ist das auch wieder eine unnötige Einschränkung.
  • Wer gibt das Singleton wieder frei? Will man keine Speicherlöcher haben, muss man sich darüber Gedanken machen. Wieder so ein Punkt der es schwer macht, Singletons korrekt zu implementieren.

Ich bin nicht der einzige, der so denkt. Um ehrlich zu sein, hab ich grad eher das Problem die interessantesten Singletons-sind-doof-Links herauszufinden. Hier mal die zwei in meinen Augen interessantesten:

  • Singleton Considered Stupid: Sehr interessanter Artikel. Der Autor beschreibt ausführlich und unterhaltsam wie er langsam an Singletons zweifelte und letztendlich zu dem Schluss kam, dass sie „böse“ sind. Selbst die, die schon durch meine bloße Aufzählung der Nachteile überzeugt sind, sollten ihn lesen.
  • Singletons are Pathological Liars: ein extremes Beispiel, wie man Singletons nicht verwenden sollte.

Aber, wenn es zustandslos ist…

Wenn das Singleton nun zustandslos ist, dann lösen sich die meisten der obigen Nachteile in Luft auf. Sind das also Beispiele für sinnvolle Singletons? Nein, denn sie sind unnötiger zusätzlicher Aufwand. So etwas realisiert man am einfachsten über Utility-Klassen, also Klassen, die nur statische Methoden haben. So spart man sich das getInstance().

Alternative Implementierungen

Es gibt noch alternative Arten der Singleton-Implementierung. Bisher ist mir aber noch keine über den Weg gelaufen, die ich wirklich gut gefunden hätte. Einzelne Nachteile werden vielleicht ausgeglichen, dabei oft jedoch neue eingeführt.

Die einfachste alternative Implementierung sind wohl statische Klassen mit Zustand. Hier ändert sich an den Nachtzeilen jedoch so gut wie gar nichts.

Einen anderen – zwar interessanten, jedoch trotzdem problematischen, Ansatz beschreibt Martin Fowler(Abschnitt „Using a Service Locator“) am Beispiel eines ServiceLocators. Durch einen Trick kann man Subclassing ermöglichen und damit auch Singletons testbar machen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Singleton
var
  private static soleInstance: Singleton;
  protected someValue: Integer; // nicht statisch!
begin
  protected virtual method doSthDyn() : Integer; // nicht statisch! Nötig um dynamische Bindung zu realisieren
  begin
    return self.someValue;  
  end method;

  public static method load(instance: Singleton);
  begin
    soleInstace := instance;
  end method;
 
  public static method doSth() : Integer;
  begin
    return soleInstance.doSthDyn(); // nötig, da statische Methoden auch statisch gebunden werden
  end method;
end class;

// Benutzung:
Singeleton.load(new Singleton.create()); // eine neue Instanz als Parameter an load() übergeben
Singleton.doSth();

Auf diese Weise gibt es immer nur eine Instanz, aber Subclassing ist möglich und Testbarkeit ist durch die Möglichkeit die Instanz, die load() übergeben wird, auszutauschen auch gegeben. Wir könnten beispielsweise eine Klasse MySingleton von Singleton ableiten und doSthDyn() überschreiben. Dann laden wir die neue Klasse und schon ist die Implementierung ersetzt:

1
2
Singleton.load(new MySingleton.create());
Singleton.doSth(); // ruft über dynamische Bindung die Methode MySingleton.doSthDyn() auf.

Problematisch ist hierbei jedoch die Methode load(). Diese lädt ja gerade dazu ein, sie noch ein zweites Mal zu benutzen. Sie ist ja da und sichtbar, warum sollte es einen Grund geben, sie nicht zu benutzen? Beispielsweise könnte man ja so die Instanz tauschen und so ein anderes Verhalten bewirken, z.B. weil der User gerade die Einstellungen geändert hat. Und dann kanns lustig werden. Machen wir mal ein Beispiel:

Wir wollen einen Blog-Reader schreiben, der anstelle eines normalen Browsers verwendet werden kann um Blogs zu lesen. Unser Singleton sei dabei ein Cache für Blog-Posts. Hier ist auch klar, dass wir nur einen Cache brauchen und mehrere sinnfrei wären, also haben wir hier schonmal unser Alibi-Argument für das Singleton. Die Klasse BlogReader benutzt also das CacheSingleton nach Fowlers Muster.

Jetzt wollen wir dem User die Möglichkeit geben, Einstellungen zum Cache vorzunehmen. Beispielsweise könnten wir einen reinen RAM-Cache haben und einen der auf die Festplatte auslagert und lassen das den User ändern. Wunderbar. Dafür haben wir ja die load()-Methode.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class BlogReader
  ....
class CacheSingleton
  ....
class RAMCache extends CacheSingleton
  ...
class HDCache extends CacheSingleton
  ...

//-------------------------
// innerhalb von BlogReader:

// wir packen irgend etwas in den Cache
// dann merken wir uns eine ID, über die wir später wieder an das Item kommen
id := CacheSingleton.store(item);

...

// User ändert etwas in der Konfiguration:
CacheSingleton.load(new RAMCache.create());
// jetzt soll auf einmal ein RAMCache genutzt werden. Der alte (HD-)Cache wird
// samt Inhalt weggeworfen (wenn wir Glück haben, haben wir sogar dran gedacht
// den frei zu geben) und ein neuer - leerer - Cache geladen.

...

CacheSingleton.get(id);
// hier übergeben wir die id, die wir oben gekriegt haben.
// Allerdings ist das Item nun nicht mehr da, weil wir jetzt ja einen neuen Cache haben.
// Der Cache wurde dem BlogReader quasi unter den Füßen weggezogen.

Das Design der Cache-Klasse ist hier nicht ganz ideal (Caches sollten nach Möglichkeit transparent sein), jedoch sollte das Beispiel klar machen, was ich meine: Bei DependencyInjection hätten wir die Möglichkeit in BlogReader zu verhindern, dass sich die Instanz ändert bzw. wir könnten eine Setter-Methode (wenn möglich über eine Property) einführen, sodass wir geordnet darauf reagieren können. Hier hat BlogReader keine Chance die Änderung zu bemerken.

Und, wenn das jetzt noch nebenläufig passiert, kann sich die Instanz des Singletons sogar innerhalb einer Methode ändern. Ja dann mal viel Spaß… Was ich damit sagen will: Auch diese Implementierungsmöglichkeit kann problematisch sein. Sie ist in mancherlei Hinsicht besser als die klassische, aber unreflektiert benutzen ist auch hier nicht sinnvoll.

Und was stattdessen nehmen?

Wie oben schon angedeutet ist DependencyInjection eine Möglichkeit viele Singletons elegant zu vermeiden. Überhaupt sollte man sich überlegen ob der der gesamte Ansatz, der einen erwägen lässt, ob man ein Singleton nimmt, der richtige ist.

Allerdings gibt es natürlich auch Fälle, bei denen Singletons gerechtfertigt sind. Nur sind diese Fälle IMHO sehr selten und man sollte sich der oben genannten Nachteile bewusst sein. Faustregel: Wenn man sich 100%ig sicher ist, dass es immer nur exakt eine einzige Instanz sein kann und DependencyInjection zu aufwändig wäre, kann man sichs überlegen.

Oftmals wird ein Logger, also eine Klasse, die Log-Dateien schreibt, als Beispiel genannt. Insbesondere der zweite Punkt, eben, dass DependencyInjection zu aufwändig wäre, ist hier schnell erfüllt. Aber kann man sich wirklich sicher sein, dass man niemals einen zweiten Logger braucht? Um beispielsweise eine zweite Logdatei, die etwas anderes beinhaltet, zu schreiben? Eine für Fehler und eine für Statistik-Daten z.B.; Kommt wohl auf den konkreten Kontext an, ob sowas möglich sein kann.

Bessere Beispiele für sinnvolle Singletons sind IMHO manche „künstliche“ Klassen, wie beispielsweise AbstractFactories (wobei es auch hier Ausnahmen gibt), sowie Klassen, die prozedural implementierte Libraries kapseln.

Fazit: Die Entscheidung, ein Singleton zu implementieren, sollte man sich gut überlegen.

17 Kommentare


  1. Schöner Artikel, regt zum Nachdenken und Diskutieren an. Hat mich aber noch nicht überzeugt, was vielleicht auch daran liegt, dass ich einiges nicht verstanden habe.

    Z.B. verstehe ich den Pseudocode im Abschnitt „Alternative Implementierungen“ nicht. (Ist das Delphi?) Wo beginnt und endet die Klassendefintion? Wo kommt das „Create()“ her? Wieso gibt es immer nur eine Instanz? Was ist eine „statische Klasse mit Zustand“?


  2. Hallo Joachim,

    Joachim Ziegler:
    Ist das Delphi?

    Das ist pascalartigeer Pseudocode. Also ja, so ähnlich wie Delphi.

    Wo beginnt und endet die Klassendefintion?

    Das ist ähnlich wie in C++. Die Klassendefinition wird in interface (entspricht dem header file) und implementation (entspricht dem cpp file) aufgeteilt. Um von implementation auf interface zu verweisen, ist es, wie in C++ auch, nötig die Klasse explizit zu benennen. Hier nur eben nicht mit ‚::‘, sondern mit ‚.‘ vom Methodenbezeichner getrennt.

    Wo kommt das “Create()” her?

    Das ist der Konstruktor. Vielleicht sollte ich dazu übergehen in Pseudocode ’new‘ zu verwenden.

    Wieso gibt es immer nur eine Instanz?

    Bei Fowlers Implementierung? Es kann prinzipiell schon mehrere Instanzen geben, nur kann nur maximal eine davon benutzt werden. Der Zugriff geschieht über statische Methoden, die über das statische Attribut soleInstace auf genau eine Instanz zugreifen können. Es ist auch nicht möglich, eine der Instanzen direkt zu benutzen, da alle öffentlichen Methoden statisch sind. Ich werde im Beispiel mal eine Implementierung von doSth() ergänzen. Vielleicht wirds dann klarer. Ich kann aber sagen, dass ich auch ne Zeit lang gebraucht hab, bis ich den Trick verstanden hab.

    mfg

    Christian


  3. So erledigt. Ich hab zum Verständnis ’new‘ ergänzt und eine Implementierung von doSth() hinzugefügt. So sollte klar werden, wie das funktioniert.


  4. OK, ich habe die Implementierung von Fowler jetzt verstanden. Mir ist aber nicht klar, warum ohne diese ein Singleton „nicht testbar“ ist bzw. warum mit dieser „testbar“. (?)

    Ist es nicht grundsätzlich die Frage, ob nicht-lokale statische Objekte immer zu verdammen sind?

    In der Software für einen Bankautomaten oder Fahrkartenautomaten oder ein Handy weißt du, dass es zu jedem Zeitpunkt immer (höchstens) einen Benutzer gibt. Über den läuft alles, der stößt alles an, der muss dauernd Auskunft über sich liefern. Warum sollst du dir das Programmieren nicht vereinfachen durch eine Zeile wie

    if( User::GetInstance()->getKontostand() < 0 ) { … }

    Anderes Beispiel: Meine Perl-Demo zum Parsen von arithmetischen Ausdrücken. Warum soll die Variable $sym, die immer das nächste Symbol der (globalen) Eingabe hält und in vielen rekursiven Prozeduren benötigt wird, nicht eine globale sein? (Die man durch ein Singleton sicherer machen kann, z.B. nur den Wert abfragen, aber das getNextSymbol() ins Singleton verlagern.)

    Bin dafür, weitere Grundsatz-Diskussionen zu Singleton ja oder nein auf die Wikipedia-Seite zu verlagern, dann haben alle was davon. Die ist Kraut und Rüben, da könnten wir aufräumen.

    Joachim

    PS: Sollte ich im RSS-Feed zu dieser Seite nicht für jeden neuen Kommentar einen neuen Eintrag sehen? Im Firefox sehe ich nur "Kommentare zu: Warum Singletons bööse sind".


  5. Mir ist aber nicht klar, warum ohne diese ein Singleton “nicht testbar” ist bzw. warum mit dieser “testbar”. (?)

    „Testbar“ heißt hier konkret, dass man die Implementierung austauschen kann. Unit-Tests sollten ja normalerweise jedes Modul separat testen. Bei GoF-Singletons kann man zwar das Singleton selbst testen, aber alle Klassen, die dieses verwenden, nicht mehr unabhängig von diesem. Man kann einfach kein Mock-Objekt erzeugen. Bei Fowlers Implementierung geht das.

    Warum sollst du dir das Programmieren nicht vereinfachen durch eine Zeile wie […]

    Die Gründe hab ich oben genannt. Ich glaub die Liste ist lang genug. Such dir was aus.

    Die Wikipedia-Seite guck ich mir mal an.

    mfg

    Christian

    P.S.:

    PS: Sollte ich im RSS-Feed zu dieser Seite nicht für jeden neuen Kommentar einen neuen Eintrag sehen? Im Firefox sehe ich nur „Kommentare zu: Warum Singletons bööse sind“.

    Also bei mir klappts. Als Reader benutze ich Liferea…



  6. Singletons sind meiner Meinung nach bei einem Problem wirklich praktisch, dazu muss man aber in eine Welt außerhalb der PCs gehen: Zu JEE Portal Servern.
    Bei Portlets ist es so, dass sie nur ein einziges Mal gestartet werden – nämlich, wenn sie das erste Mal aufgerufen werden. Singletons, die über statische Felder realisiert werden, haben hier einen riesigen Vorteil: Komplexe Vorgänge, die während der gesamten Laufzeit nur ein einziges Mal ausgeführt werden müssen und ein Objekt produzieren, das an den verschiedensten Stellen benötigt wird, werden wunderbar gekapselt und das Objekt kann über das Singleton auch gleich noch bereitgestellt werden.

    Die Besonderheit ist hier, dass das Singleton keine Instanz von sich selber vorhalten muss, sondern auch eine andere Klasse permanent im Speicher halten kann.


  7. Singletons, die über statische Felder realisiert werden

    Meinst du Utility-Klassen?

    Die Besonderheit ist hier, dass das Singleton keine Instanz von sich selber vorhalten muss, sondern auch eine andere Klasse permanent im Speicher halten kann.

    Das versteh ich nicht ganz, was meinst du damit?

    Kenn mich mit Portlets nicht aus, aber ich seh momentan noch nicht so ganz den Vorteil, von dem du sprichst. Was konkret machst das Singleton da einfacher?

    mfg

    Christian


  8. Das versteh ich nicht ganz, was meinst du damit?

    Du kannst doch eine Java-Klasse mit statischen Feldern definieren:

    1
    2
    3
    4
    5
    6
    7
    public class Irgendwas {
      protected static Irgendwas irgendwas = new Irgendwas();

      public static Irgendwas getIrgendwas() {
        return irgendwas;
      }
    }

    Angenommen, du benötigst permanent eine Instanz einer anderen Klasse, z.B. einer DistributedMap, dann kannst du das über 2 mögliche Wege realisieren. Fall1 : Du erweiterst die benötigte Klasse:

    1
    2
    3
    4
    5
    6
    7
    public class SingleDistributedMap extends DistributedMap {
      protected static SingleDistributedMap singleDistributedMap = new SingleDistributedMap();

      public static SingleDistributedMap getSingleDistributedMap() {
        return singleDistributedMap;
      }
    }

    Die andere Möglichkeit ist, dass du eine neue Klasse erstellst, die das benötigte Objekt vorhält. Der Vorteil ist, dass man damit mehrere Objekte in einem Singleton permanent vorhalten kann:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class SingleDistributedMap {
      protected static SingleDistributedMap singleDistributedMap = new SingleDistributedMap();

      protected DistributedMap distributedMap = new DistributedMap();

      public static SingleDistributedMap getSingleDistributedMap() {
        return singleDistributedMap;
      }

      public DistributedMap getDistributedMap() {
        return distributedMap;
      }
    }

    Okay, die dritte Variante ist eigentlich kein Singleton mehr, lässt sich durch die statischen Variablen jedoch ähnlich nutzen. Auch diese Klasse kann mehrere Objekte permanent im Speicher halten:

    1
    2
    3
    4
    5
    6
    7
    public class SingleDistributedMap {
      protected static DistributedMap distributedMap = new DistributedMap();

      public static DistributedMap getDistributedMap() {
        return distributedMap;
      }
    }

  9. Achso! Vielleicht noch der Vorteil des ganzen direkt am Beispiel der DistributedMap: Um solch eine DistributedMap aus der Konfiguration des Application Server zu erhalten, muss man sich via JNDI die entsprechende Referenz besorgen. Jetzt stell‘ dir vor, du hast 100 Auftritte, bei denen jeweils mehrere 1000 Besucher stündlich vorbei kommen und für jeden Besucher in jedem Auftritt müsste diese Referenz herausgesucht werden. Dann bist du bei über 2.400.000 Abfragen täglich, nur um diese eine Referenz abzufragen. Oooder du hast ein Singleton, in dem diese Referenz permanent im Speicher vorgehalten wird. Die Referenz wird dann nur ein einziges Mal abgerufen, nämlich, wenn die Klasse in den Speicher geladen wird.


  10. Oooder du hast ein Singleton, in dem diese Referenz permanent im Speicher vorgehalten wird. Die Referenz wird dann nur ein einziges Mal abgerufen, nämlich, wenn die Klasse in den Speicher geladen wird.

    Dazu braucht man aber doch kein Singleton. Das geht doch auch mit ner Klasse, die eben nur einmal instanziiert wird. Oder versteh ich da was falsch? Hab mich mit Application-Servern noch nicht auseinander gesetzt.

    Ich für meinen Teil verwende Singletons nur dann, wenn:
    – mehrfache Instanziierung der Klasse schädlich wäre
    – ggf. zur Kapselung prozeduraler Libs (kommt drauf an; oft gibts da auch ne bessere Lösung)
    – für Klassen, die von Natur aus statisch sind (Abstract Factory, Registrys, …) und ne Utility-Klasse aus irgend einem Grund nicht geht.

    Kannst du deinen Fall da irgend wo einordnen? Oder hab ich was vergessen?

    mfg

    Christian


  11. Ja, aber genau das macht doch ein Singleton. Sicher gehen, dass eine Klasse nur genau einmal instanziert wird! Alles weitere wäre doch unnötiger Overhead (Stichwort 2,4 Mio. Abfragen pro Tag). Wir sorgen mit dem Singleton vor allem dafür, dass wir uns nicht selber darum kümmern müssen, die Instanz mitzuschleppen. Das macht der Application Server für uns.

    Wie ich gerade gelesen habe, sind die 2te und 4te von mir gezeigte Variante anscheinend sogar die besseren.

    Jetzt ist die Frage, ob 2,4 Millionen unnötige Abfragen schädlich sind. Für die Performance auf alle Fälle 😉 . Ansonsten könnte ich diesen Fall nirgendwo einordnen.


  12. Ja, aber genau das macht doch ein Singleton. Sicher gehen, dass eine Klasse nur genau einmal instanziert wird!

    Da ist ein kleiner aber feiner Unterschied: Ein Singleton stellt sicher, dass eine Klasse nur einmal instanziiert wird. Das ist etwas anderes, als sicher stellen, dass aus Performancegründen eine Abfrage nur einmal gemacht wird o.ä.

    Für die Performance-Geschichte täte es ein einfacher Caching-Proxy oder eine Fassade auch.

    Wir sorgen mit dem Singleton vor allem dafür, dass wir uns nicht selber darum kümmern müssen, die Instanz mitzuschleppen. Das macht der Application Server für uns.

    Das ist das, was das Singleton macht: Es macht eine Instanz global. Das kann man machen, wenn man weiß, was man tut und die Nachteile kennt (Das ist die Aussage meines Blog-Artikels). Da muss man im Einzelfall abwägen, was sinnvoll ist und was nicht. Wie das in deinem Fall ist, wage ich nicht zu beurteilen. Dazu fehlt mir der Hintergrund. Ich glaube dir jetzt also einfach mal, dass es sinnvoll ist…

    mfg

    Christian


  13. Ich hab mal auf meine neue Pseudocode-Syntax aktualisiert.



  14. Ich selber programmiere vorwiegend Maschinensteuerungen auch bekannt als Embedded Lösungen auf C++ Basis. Zur Erklärung des Autor „Es führt (unnötige) Beschränkungen ein. Wenn in einer späteren Programmversion nun doch mehr als eine Instanz von Nöten ist, muss das Singleton mühsam entfernt werden.“
    Es ist mir noch nie untergekommen das auf einem Tag auf den Anderen sich die Maschine substantiell verändert hat, sprich auf einmal ist ein Motor mehr da oder ein Ventil mehr. Genau das ist Objektorientierte programmieren wenn es nur eines von einem Gewissen Element an der Maschine hat sollte es auch nur eins geben.
    Für mich ist Objektorientiertes programmieren in erster Line die Abbildung der Komponenten an einer Maschine. So findet sich wer die Maschinen kennt auch in der Software zurecht.


  15. Du sagst da etwas sehr Richtiges: Du bildest mit deiner Software die zu automatisierende Realität ab, damit du dich leichter zurecht findest. Das ist das Modellprinzip.

    Eine Sache, die dabei eine Rolle spielt, ist der Unterschied zwischen Klasse und Instanz. Deine Maschine hat einen Motor dieser konkrete Motor, ist eine Instanz der Klasse Motor. Es gibt nur einen Motor, also nur eine Instanz des Motors. Ein zweiter Motor ist nicht vorhanden, wäre aber logisch denkbar. Singletons sind dazu da, sicher zu stellen, dass es nur eine Instanz überhaupt geben kann. Das ist also genau für so Fälle, in denen eine zweite Instanz widersinnig wäre.

    Beispiele dafür nennt schon das GoF-Book:
    – ein System hat vielleicht nur einen Drucker, könnte aber mehrere Drucker haben, *darf* aber nur einen PrinterSpooler haben.
    – in einem unixioden System kann es nur eine Dateisystemhierarchie geben. Es wäre widersinnig das Wurzelverzeichnis „/“ mehrmals zu haben.
    – von einen WindowManager kann es logisch auch nur eine einzige Instanz geben. Andernfalls kommen die sich beim Verwalten der Ressourcen in die Quere.
    – ganz typisch sind auch rein technische Klassen wie eine AbstractFactory. Mehrere Instanzen einer solchen zu haben, macht auch keinen Sinn.

    An den Beispielen sieht man schon, dass das oft auch nur Design-Entscheidungen sind: Unter Windows gibt es mehrere Dateisystem-Wurzeln. Mehr oder weniger zumindest.

    Jedenfalls sind das die Fälle, für die Singletons gedacht sind. Auch, wenn du in deinem Anwendungsfall niemals die Situation hast, dass deine Software mit zwei Motoren auskommen muss und du dir sicher bist, dass du deinen Code niemals für eine andere Maschine portieren musst, bei der deine Annahmen nicht mehr gelten, bedeutet das nicht, dass das Argument an sich nicht anwendbar wäre. Und die anderen genannten Nachteile hast du natürlich trotzdem. Ich mag GoF-Singletons also weiterhin nicht und setze sie nur sehr selten und sehr vorsichtig ein.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert