Ich habe mich immer gefragt, ob ich zu viel oder zu wenig nachdenke, bevor ich etwas programmiere. Dies gilt insbesondere für mich, wenn ich mir nicht sicher bin, welche möglichen zukünftigen Änderungen ich vornehmen muss. Ich weiß nicht, wie flexibel oder abstrahiert ich meinen Unterricht machen sollte. Ich werde ein kurzes Beispiel geben.
Sie möchten ein Programm schreiben, das Blackjack gegen einen Computer spielt, und Sie sind der Typ Mensch, der gerne experimentiert. Sie fangen an, den Code für das Deck zu schreiben, aber dann erkennen Sie, dass Blackjack 1, 2, 4 oder eine beliebige Anzahl von Decks haben könnte. Sie erklären das, aber dann erkennen Sie, dass das Deck vielleicht verändert wird und keine Karten von Wert zehn haben. Du entscheidest dann, dass das Deck vielseitig einsetzbar sein soll, um eine beliebige Anzahl von Farben oder Reihen zu erlauben. Du entscheidest dann, dass die Regeln für das Deck von der Standardanzahl an Anzügen multipliziert mit den einzigartigen Rängen geändert werden können, um der Gesamtmenge der Karten im Deck zu entsprechen ... Du kannst sehen, wohin ich hier gehe.
Meine Frage ist, gibt es irgendwelche Richtlinien dafür, wie flexibel eine Klasse sein sollte?
Favorisieren Sie Minimalismus und Einkapselung und vermeiden Sie Funktionen, die Sie nicht brauchen.
Es ist natürlich gut, nach Bedürfnissen zu entwerfen, aber Designs mit Dingen, die Sie nicht verwenden - oder die in Zukunft möglicherweise verwendet werden könnten - zu überladen - sollten minimiert werden. Es ist in Ordnung, zu überlegen und umzusetzen, was Sie sicher brauchen.
Wenn Sie ein "zukünftiges Problem" verstehen und spezifizieren (speziell an diesem Punkt in der Zukunft), werden Sie es oft anders als die heutige Lösung lösen.
Sehen Sie sich das großartige Papier " zu den Kriterien an, die bei der Zerlegung von Systemen in Module verwendet werden "von David Parnas, von zurück in 1972 .
Im Allgemeinen sollten Sie versuchen Verantwortungsbereiche zu identifizieren , die hinter einer sehr einfachen Schnittstelle eingefügt werden können, die nützliche Funktionalität und Komplexität verbirgt. Sie sollten danach streben, das was von dem wie in Bereichen zu trennen, die Sie am ehesten ändern (d. H. Abweichungen vorhersagen).
Flexibilität ist in der Tat eine Voraussetzung dafür, dass eine Anwendung / ein System gewartet werden kann. Normalerweise finde ich, dass ein Entwurf, der dem SOLID-Design-Prinzip, TDD und zustandslosen Geschäftslogik folgt, einfacher zu warten ist.
Unter allen SOLID-Prinzipien finde ich, dass [S] RP die Regel ist, die die Anwendung wartbar macht. Nach [S] RP wird Ihr System in kleinere Teile mit austauschbaren Klassen aufgeteilt. Angenommen, es kann in Deck
, DeckRule
, HitAction
usw. gebrochen werden.
Interface oder Vererbung wird helfen, da Sie Ihre Deck
leicht mit NoTenDeck
oder SpadeOnlyDeck
austauschen können. Und Sie können die DeckRule
auf HardToWinDeckRule
oder ImpossibleWinDeckRule
tauschen. Mit decorator
oder anderen Entwurfsmustern wie composite
wird auch dazu beitragen, Ihr System flexibel zu machen. Vergessen Sie nicht Test Unit, es wird Ihnen helfen, den Code zu refaktorieren.
Und manchmal brauchen Sie auch etwas wie Breaking Change
, in dem Sie Ihre aktuelle Architektur und Schnittstellen abreißen müssen, um sie durch ein anderes Design zu ersetzen. Manchmal ist es notwendig, aber meistens nicht.
Sie können mehrere Diskussionen bei stackoverflow finden Antwort für DI gegen Singleton und wenig über Staat oder Staatenlose .
Ich versuche dem agilen Prinzip von YAGNI zu folgen! - Sie werden es nicht brauchen.
Es lohnt sich nicht, sich all diese möglichen zukünftigen Anforderungen zu überlegen. Es gibt unendlich viele mögliche zukünftige Anforderungen. Sie können nicht alle erklären. Tun Sie einfach, was Sie tun müssen, um die Anforderungen zu erfüllen, die Sie bereits haben.
Wenn Sie in Zukunft neue Anforderungen bekommen, dann ändern Sie das System. (Sie haben gute Tests, um sicherzustellen, dass Sie beim Refactoring nichts kaputt machen?)
Allgemeine Überlegungen zur Flexibilität
Nach Ihrer Beschreibung des Problems glaube ich nicht, dass Ihre Klassen flexibel sein sollten, da "jeden neuen Aspekt der Spielregeln in dieselbe Klasse werfen" . Eine Klasse mit zu vielen Verantwortlichkeiten ist zerbrechlich, schwer zu pflegen und daher schwer zu ändern - ironischerweise wird das Behandeln einer Klasse, als ob sie flexibel wäre, sie schließlich steif machen! Legen Sie nicht alle Ihre Eier in einen Korb. Getrenntes Anliegen bedeutet separate Klasse. Ihr Gesamtdesign sollte flexibel sein, nicht so sehr Ihre Klassen.
Beim Blackjack-Problem
Kartenspiele, besonders komplexe und / oder sich entwickelnde Kartenspiele, sind im Allgemeinen sehr eigenartige Tiere und daher wahrscheinlich kein gutes Standardbeispiel, mit dem man experimentieren kann, wenn man versucht, seine Designfähigkeiten zu verbessern.
Wenn Sie echte Modularität wünschen, benötigen Sie wahrscheinlich eine Pluggable-Regel-Engine, die Plugins in verschiedenen Phasen eines Spiels hooken lässt und Ihnen Zugriff auf relevante Ressourcen gewährt, um alles von Scores bis zur Abfolge von Ereignissen in einer Runde zu ändern noch andere Regeln.
Meine Meinung zu diesem Thema ist
"I ain't gonna need this rule/type of hook into the game"
anstatt in "I ain't gonna need a rules engine"
, da Sie wissen, dass Sie es müssen hab sowieso einen. Oder
Sie können sich auch die Ссылка für spielspezifische Designrichtlinien ansehen.
Wenn ich Code schreibe, tendiere ich dazu, Dinge zu suchen, die später offensichtlich sind. "Offensichtlich ist es wahrscheinlich ein Wort zu definieren. :-) Es bedeutet Dinge, von denen du sicher bist, dass sie in einer zukünftigen Version sein werden. Ansonsten versuche ich, mich nicht darum zu sorgen.
Tags und Links design-patterns architecture oop