Viele Leute scheinen zuzustimmen, dass das Singleton-Muster eine Reihe von Nachteilen aufweist, und einige schlagen sogar vor, das Muster vollständig zu vermeiden. Hier gibt es eine ausgezeichnete Diskussion . Bitte richten Sie alle Kommentare zum Singleton-Muster auf diese Frage.
Meine Frage : Gibt es andere Designmuster, die vermieden oder mit großer Sorgfalt verwendet werden sollten?
design-patterns
anti-patterns
Brian Rasmussen
quelle
quelle
Antworten:
Muster sind komplex
Alle Designmuster sollten mit Vorsicht verwendet werden. Meiner Meinung nach sollten Sie Muster umgestalten, wenn es einen triftigen Grund dafür gibt, anstatt sofort ein Muster zu implementieren. Das allgemeine Problem bei der Verwendung von Mustern besteht darin, dass sie die Komplexität erhöhen. Die übermäßige Verwendung von Mustern erschwert die Weiterentwicklung und Wartung einer bestimmten Anwendung oder eines bestimmten Systems.
Meistens gibt es eine einfache Lösung, und Sie müssen kein bestimmtes Muster anwenden. Eine gute Faustregel ist, ein Muster zu verwenden, wenn Codeteile häufig ersetzt werden oder häufig geändert werden müssen, und bereit zu sein, die Einschränkung des komplexen Codes bei der Verwendung eines Musters zu übernehmen.
Denken Sie daran, dass Ihr Ziel die Einfachheit sein und ein Muster verwenden sollte, wenn Sie eine praktische Notwendigkeit sehen, Änderungen in Ihrem Code zu unterstützen.
Prinzipien über Muster
Es mag umstritten erscheinen, Muster zu verwenden, wenn sie offensichtlich zu überentwickelten und komplexen Lösungen führen können. Stattdessen ist es für einen Programmierer viel interessanter, sich über Entwurfstechniken und -prinzipien zu informieren, die die Grundlage für die meisten Muster bilden. Tatsächlich betont eines meiner Lieblingsbücher über „Entwurfsmuster“ dies, indem es wiederholt, welche Prinzipien auf das betreffende Muster anwendbar sind. Sie sind einfach genug, um in Bezug auf die Relevanz nützlicher zu sein als Muster. Einige der Prinzipien sind allgemein genug, um mehr als objektorientierte Programmierung (OOP) zu umfassen, wie z. B. das Liskov-Substitutionsprinzip , solange Sie Module Ihres Codes erstellen können.
Es gibt eine Vielzahl von Gestaltungsprinzipien, aber die im ersten Kapitel des GoF-Buches beschriebenen sind zunächst sehr nützlich.
Lass die für eine Weile in dir versinken. Es sollte beachtet werden, dass eine Schnittstelle beim Schreiben von GoF alles bedeutet, was eine Abstraktion ist (was auch Superklassen bedeutet), nicht zu verwechseln mit der Schnittstelle als Typ in Java oder C #. Das zweite Prinzip beruht auf der beobachteten Überbeanspruchung der Vererbung, die heute leider noch weit verbreitet ist .
Von dort aus können Sie sich über SOLID-Prinzipien informieren, die von Robert Cecil Martin (auch bekannt als Onkel Bob) bekannt gemacht wurden . Scott Hanselman interviewte Onkel Bob in einem Podcast über diese Prinzipien :
Diese Grundsätze sind ein guter Anfang, um sie zu lesen und mit Ihren Kollegen zu diskutieren. Möglicherweise stellen Sie fest, dass die Prinzipien miteinander und mit anderen Prozessen wie der Trennung von Bedenken und der Abhängigkeitsinjektion verwoben sind . Nachdem Sie eine Weile TDD durchgeführt haben, stellen Sie möglicherweise auch fest, dass diese Prinzipien in der Praxis selbstverständlich sind, da Sie sie bis zu einem gewissen Grad befolgen müssen, um isolierte und wiederholbare Komponententests zu erstellen .
quelle
Das, worüber sich die Autoren von Design Patterns am meisten Sorgen machten, war das "Besuchermuster".
Es ist ein "notwendiges Übel" - wird aber oft überstrapaziert und die Notwendigkeit zeigt oft einen grundlegenderen Fehler in Ihrem Design.
Ein alternativer Name für das Muster "Besucher" ist "Mehrfachversand", da das Besuchermuster genau das ist, was Sie erhalten, wenn Sie eine Versand-OO-Sprache mit einem Typ verwenden möchten, um den zu verwendenden Code basierend auf dem Typ von zwei auszuwählen (oder mehr) verschiedene Objekte.
Das klassische Beispiel ist, dass Sie den Schnittpunkt zwischen zwei Formen haben, aber es gibt einen noch einfacheren Fall, der oft übersehen wird: den Vergleich der Gleichheit zweier heterogener Objekte.
Wie auch immer, oft hat man so etwas:
Das Problem dabei ist, dass Sie alle Ihre Implementierungen von "IShape" miteinander gekoppelt haben. Sie haben impliziert, dass Sie, wenn Sie der Hierarchie eine neue Form hinzufügen möchten, auch alle anderen "Form" -Implementierungen ändern müssen.
Manchmal ist dies das richtige Minimal-Design - aber denken Sie darüber nach. Erfordert Ihr Design wirklich , dass Sie zwei Typen versenden müssen? Sind Sie bereit, jede der kombinatorischen Explosionen von Multi-Methoden zu schreiben?
Durch die Einführung eines anderen Konzepts können Sie häufig die Anzahl der Kombinationen reduzieren, die Sie tatsächlich schreiben müssen:
Natürlich kommt es darauf an - manchmal muss man wirklich Code schreiben, um all diese verschiedenen Fälle zu behandeln -, aber es lohnt sich, eine Pause einzulegen und nachzudenken, bevor man den Sprung wagt und Visitor verwendet. Es könnte Ihnen später viel Schmerz ersparen.
quelle
Singletons - Eine Klasse, die Singleton X verwendet, hat eine Abhängigkeit davon, die für Tests schwer zu erkennen und zu isolieren ist.
Sie werden sehr oft verwendet, weil sie bequem und leicht zu verstehen sind, aber sie können das Testen wirklich erschweren.
Siehe Singletons sind pathologische Lügner .
quelle
Ich glaube, dass das Muster der Vorlagenmethode im Allgemeinen ein sehr gefährliches Muster ist.
quelle
Ich denke nicht, dass Sie Design Patterns (DP) vermeiden sollten, und ich denke nicht, dass Sie sich zwingen sollten, DPs bei der Planung Ihrer Architektur zu verwenden. Wir sollten DPs nur verwenden, wenn sie natürlich aus unserer Planung hervorgehen.
Wenn wir von Anfang an definieren, dass wir einen bestimmten DP verwenden möchten, werden viele unserer zukünftigen Entwurfsentscheidungen von dieser Wahl beeinflusst, ohne dass garantiert wird, dass der von uns ausgewählte DP für unsere Anforderungen geeignet ist.
Eine Sache, die wir auch nicht tun sollten, ist, einen DP als unveränderliche Einheit zu behandeln, wir sollten das Muster an unsere Bedürfnisse anpassen.
Zusammenfassend denke ich also nicht, dass wir DPs vermeiden sollten, wir sollten sie annehmen, wenn sie in unserer Architektur bereits Gestalt annehmen.
quelle
Ich denke, dass Active Record ein überstrapaziertes Muster ist, das das Mischen von Geschäftslogik mit dem Persistenzcode fördert. Es ist nicht sehr gut, die Speicherimplementierung vor der Modellebene zu verbergen und die Modelle an eine Datenbank zu binden. Es gibt viele Alternativen (in PoEAA beschrieben) wie Table Data Gateway, Row Data Gateway und Data Mapper, die häufig eine bessere Lösung bieten und sicherlich dazu beitragen, den Speicher besser zu abstrahieren. Außerdem sollte Ihr Modell nicht braucht in einer Datenbank gespeichert werden; Was ist mit dem Speichern als XML oder dem Zugriff über Webdienste? Wie einfach wäre es, den Speichermechanismus Ihrer Modelle zu ändern?
Trotzdem ist Active Record nicht immer schlecht und eignet sich perfekt für einfachere Anwendungen, bei denen die anderen Optionen übertrieben wären.
quelle
Es ist ganz einfach ... Vermeiden Sie Designmuster, die Ihnen nicht klar sind oder in denen Sie sich nicht wohl fühlen .
Um nur einige zu nennen ...
Es gibt einige unpraktische Muster , wie z.
Interpreter
Flyweight
es gibt auch einige schwerer zu erfassen , wie zB:
Abstract Factory
- Ein vollständiges abstraktes Fabrikmuster mit Familien erstellter Objekte ist kein Kinderspiel, wie es scheintBridge
- Kann zu abstrakt werden, wenn Abstraktion und Implementierung in Teilbäume unterteilt sind, ist aber in einigen Fällen ein sehr brauchbares MusterVisitor
- Das Verständnis des doppelten Versandmechanismus ist wirklich ein MUSSund es gibt einige Muster, die furchtbar einfach aussehen , aber aus verschiedenen Gründen, die mit ihrem Prinzip oder ihrer Umsetzung zusammenhängen , keine so klare Wahl sind :
Singleton
- nicht wirklich total schlechtes Muster, nur zu überstrapaziert (oft dort, wo es nicht geeignet ist)Observer
- Tolles Muster ... macht das Lesen und Debuggen von Code nur viel schwierigerPrototype
- tauscht Compiler-Checks auf Dynamik aus (was gut oder schlecht sein kann ... hängt davon ab)Chain of responsibility
- zu oft nur zwangsweise / künstlich in das Design hineingedrücktFür diese "unpraktischen" sollte man wirklich überlegen, bevor man sie verwendet, da es normalerweise irgendwo eine elegantere Lösung gibt.
Für die "schwerer zu fassenden" ... sind sie wirklich eine große Hilfe, wenn sie an geeigneten Stellen verwendet werden und wenn sie gut implementiert sind ... aber sie sind ein Albtraum, wenn sie unsachgemäß verwendet werden.
Nun, was kommt als nächstes ...
quelle
Ich hoffe, ich werde dafür nicht zu sehr geschlagen. Christer Ericsson hat in seinem Echtzeit-Blog zur Kollisionserkennung zwei Artikel ( eins , zwei ) zum Thema Entwurfsmuster geschrieben . Sein Ton ist ziemlich hart und vielleicht ein bisschen provokativ, aber der Mann kennt sich aus, also würde ich es nicht als Schwärmerei eines Verrückten abtun.
quelle
Einige sagen, dass der Service Locator ein Anti-Pattern ist.
quelle
Ich glaube, das Beobachtermuster hat eine Menge zu verantworten, es funktioniert in sehr allgemeinen Fällen, aber wenn Systeme komplexer werden, wird es zu einem Albtraum, der OnBefore () -, OnAfter () - Benachrichtigungen und häufig das Posten asynchroner Aufgaben erfordert, um eine erneute Verwendung zu vermeiden Eingang. Eine viel bessere Lösung besteht darin, ein System zur automatischen Abhängigkeitsanalyse zu entwickeln, das alle Objektzugriffe (mit Lesebarrieren) während der Berechnungen instrumentiert und automatisch eine Kante in einem Abhängigkeitsdiagramm erstellt.
quelle
Eine Ergänzung zu Spoikes Beitrag " Refactoring to Patterns" ist eine gute Lektüre.
quelle
Iterator ist ein weiteres GoF-Muster, das vermieden oder zumindest nur verwendet werden sollte, wenn keine der Alternativen verfügbar ist.
Alternativen sind:
für jede Schleife. Diese Konstruktion ist in den meisten gängigen Sprachen vorhanden und kann in den meisten Fällen verwendet werden, um Iteratoren zu vermeiden.
Selektoren à la LINQ oder jQuery. Sie sollten verwendet werden, wenn for-each nicht geeignet ist, da nicht alle Objekte aus dem Container verarbeitet werden sollten. Im Gegensatz zu Iteratoren können Selektoren an einer Stelle angeben, welche Art von Objekten verarbeitet werden sollen.
quelle
yield
Iterator ermöglicht. Eric White hat in C # 3.0 eine großartige Diskussion darüber: blogs.msdn.com/b/ericwhite/archive/2006/10/04/… . Lesen Sie auch die Diskussion von Jeremy Likness über Coroutinen mit Iteratoren: wintellect.com/CS/blogs/jlikness/archive/2010/03/23/… .