Muster sollten nur verwendet werden, wenn sie die beste Lösung sind oder bei der Erstellung einer guten Lösung helfen können (stimmen Sie zu?).
Ich sehe Designmuster ausschließlich als Implementierungsdetails. Wenn Sie Ihre öffentlichen APIs und Programme in dieser Dokumentation dokumentieren, spielt es im Allgemeinen keine Rolle (oder beeinflusst Sie stark), wo Sie Entwurfsmuster haben. Das heißt, Sie sagen nicht "Ich habe hier ein Brückenmuster und ich werde einen Besucher darüber implementieren". Stattdessen heißt es: "Diese Klasse wird auf verschiedenen Betriebssystemen unterschiedliche Implementierungen haben, sodass sie unter Verwendung eines Brückenmusters implementiert wird." Wenn Sie es dann verwenden, ist es Ihnen gleichgültig, ob es als Bridge implementiert wird - da Sie sich die öffentliche API und nicht das Bridge-Muster ansehen.
Wie viel Aufwand sollte man tatsächlich in die Schaffung lose gekoppelter, flexibler Designs investieren?
Eine lose Kopplung kann durch Befolgen eines einfachen Regelwerks erreicht werden. Wenn Sie diese respektieren, wird Ihr Code beim Schreiben (mehr) lose gekoppelt (dh jeder Aufwand ist bereits Teil des Entwicklungsprozesses).
Unter den Regeln (keine vollständige Liste):
- Definieren Sie Ihre Schnittstellen, indem Sie Client-Code denken (oder schreiben) (wie die Klasse verwendet wird), nicht was die Klasse tun wird (dh die Schnittstelle entwerfen, nicht implementieren).
- "sag, frag nicht"
- Konstruieren Sie Objekte aus bereits erstellten Teilen
- Übergeben Sie die tatsächlichen Objekte, die Sie verwenden werden, an den Konstruktor (keine Fabriken für die Mitglieder, Parameter für die Fabriken der Parameter oder ähnliches).
- TROCKEN (Wenn Sie zwei Zeilen haben, die an zwei Stellen in derselben Reihenfolge angezeigt werden, extrahieren Sie sie in eine separate Funktion usw.).
- Wenn die Erstellung eines Objekts eine komplexere Operation ist, implementieren Sie die Erstellung der Zwischenteile als Factory-Methode / -Klasse (dh nicht im Konstruktorkörper).
- YAGNI (erstelle Dinge so, wie du sie brauchst, nicht vorher).
Diese Regeln werden je nach Sprache, Entwicklungsmethode Ihres Teams (z. B. TDD), Zeitbudgetbeschränkungen usw. unterschiedlich befolgt.
In Java empfiehlt es sich beispielsweise, Ihre Schnittstelle als zu definieren interface
und Clientcode darauf zu schreiben (instanziieren Sie dann die Schnittstelle mit einer Implementierungsklasse).
In C ++ hingegen haben Sie keine Schnittstellen, sodass Sie die Schnittstelle nur als abstrakte Basisklasse schreiben können. Da Sie in C ++ die Vererbung nur verwenden, wenn Sie eine starke Anforderung dafür haben (und als solche den Overhead unnötiger virtueller Funktionen vermeiden), werden Sie die Schnittstelle wahrscheinlich nicht separat definieren, sondern nur den Klassenkopf.
Diejenigen, die sich Designmustern widersetzen, sagen, dass die Kosten für die Verwendung dieser Muster häufig die Vorteile überwiegen.
Ich denke, sie machen es falsch. Wenn Sie lose gekoppelten (und DRY-) Code schreiben, ist die Integration von Entwurfsmustern mit minimalem zusätzlichen Aufwand erforderlich. Andernfalls müssen Sie Ihren Code anpassen, um ein Entwurfsmuster zu implementieren.
Wenn Sie viele Änderungen vornehmen müssen, um ein Entwurfsmuster zu implementieren, liegt Ihr Problem nicht im Entwurfsmuster, sondern darin, dass Ihre Codebasis monolithisch und eng gekoppelt ist. Dies ist ein schlechtes / suboptimales Designproblem, kein Designmusterproblem.
Was ich wissen möchte, ist, wie viel Aufwand ich tatsächlich in die Erstellung zusätzlicher Abstraktionsebenen und Designs investieren sollte, damit meine Anwendung OO-Prinzipien wie lose Kopplung, Programmierung an eine Schnittstelle usw. folgen kann. Lohnt es sich wirklich? es? Wie viel Aufwand sollte ich in diese investieren?
Ihre Fragen gehen von der (nicht angegebenen) Annahme aus, dass der einzige Vorteil der losen Kopplung die Fähigkeit ist, Entwurfsmuster einfach zu implementieren. Es ist nicht.
Zu den Vorteilen der losen Kupplung gehören:
- Flexibilität bei Umgestaltung und Neugestaltung
- weniger verschwendete Mühe
- Testbarkeit
- erhöhte Möglichkeit, den Code wiederzuverwenden
- Design Einfachheit
- weniger Zeit im Debugger verbracht
... und ein paar andere, die mir momentan nicht in den Sinn kommen.