Feststellung
Ich möchte es nach und nach über ein oder zwei Monate lesen.
Dies ist mein eigenes Memo.
- 2020-07-05 Da es überflüssig geworden ist, werde ich es zusammenfassen und mich nach dem Lesen weiter auf den Beispielcode konzentrieren.
Der Punkt
Überblick und Einführung der objektorientierten Programmierung
1. Objektorientiertes Design
1.1 Design Lob
- Wenn Sie der objektorientierten Entwurfsmethode folgen, können Sie die Codierung genießen und Software am effizientesten produzieren!
- Objektorientiertes Design = Verwalten von Abhängigkeiten.
--Teile
- Objekt
- Interaktion
--Botschaft
- Der Zweck des Entwurfs besteht darin, die Änderungskosten zu senken.
1.2 Entwurfswerkzeuge
- Konstruktionsprinzip "FEST"
- Entwurfsmuster "GoF"
1.3 Akt der Gestaltung
- Die Bedeutung von "Design" unterscheidet sich zwischen BUFD (Wasserfall?) Und objektorientiertem Design.
- Vollständige Dokumentation, die das zukünftige interne Verhalten identifiziert.
- Objektorientiertes Design
- Codestruktur in einem kleinen Bereich unter der Annahme von Änderungen.
1.4 Einfache Einführung in die objektorientierte Programmierung
- Verfahrenssprache
--Variationen haben einen Datentyp.
- Daten und Verhalten sind unterschiedlich.
- Objektorientierte Sprache
- Das Objekt hat Verhalten.
- Hat viele Typen (= Klassen).
- Sie können das Verhalten des Objekts vorhersagen.
- Objektorientierte Sprachen können Typen erweitern. Daher werden objektorientierte Anwendungen zu einer speziellen und einzigartigen Programmiersprache, die von Programmierern verwendet wird.
Konzentriere dich auf die Klasse
2. Entwerfen Sie eine einzelne Verantwortungsklasse
- Es gibt zwei verschiedene Kriterien für das Ziel der Modellierung einer Anwendung.
--Verwenden Sie Klassen, um die erforderlichen Aktionen "sofort" auszuführen.
- Machen Sie es einfach, „danach“ zu wechseln.
――Der Teil, in dem die technischen Programmierfähigkeiten deutlich erkennbar sind.
2.1 Entscheiden Sie, was zur Klasse gehört
- Der erste Schritt zum Schreiben von TRUE-Code besteht darin, sicherzustellen, dass Sie eine einzige Verantwortung haben (= minimal und nützlich).
2.2 Erstellen Sie eine Klasse mit einer einzigen Verantwortung
- Alle Klassen und Methoden haben eine einzige Verantwortung.
――Was ist Einzelverantwortung?
- Wenn Sie die Methode der Klasse in eine Frage umschreiben, wird sie zu einer aussagekräftigen Frage.
- Sie können die Klasse in einem Satz erklären.
- "Es" und "oder" sind nicht enthalten.
2.3 Schreiben Sie Code, der Änderungen begrüßt
- Instanzvariablen und Datenstrukturen ausblenden = Verhaltensänderung (Methode).
- Verhindern Sie, dass unerwartete Änderungen Ihren Code beeinflussen.
- Sobald alle Methoden eine einzige Verantwortung haben, wird der Umfang der Klasse klar.
3. Verwalten von Abhängigkeiten
- Arten des Objektverhaltens
- Verhalten, das die Klasse selbst unabhängig implementieren sollte
- Vererbung von Verhalten
- Verhalten wird in anderen Objekten implementiert
3-1. Abhängigkeiten verstehen
- Abhängigkeiten bestehen, wenn das Objekt weiß:
- Namen anderer Klassen
- Der Name der Nachricht, die an andere Objekte als "self" gesendet wurde
- Für die Nachricht erforderliche Argumente
- Reihenfolge dieser Argumente
- Minimieren Sie Abhängigkeiten, sodass Codeänderungen nicht groß genug sind, um Änderungen an anderen Objekten zu erzwingen.
3-2. Schreiben Sie lose gekoppelten Code
- Abhängigkeit ist schlecht.
――Dependenz ist wie ein fremdes Bakterium, das versucht, eine Klasse zusammenzudrücken (zu entwerfen).
- Wenn es Namen anderer Klassen gibt
- Abhängige Objekte injizieren
- Sie müssen den Klassennamen anderer Objekte nicht kennen und können den Join trennen.
- Wenn Sie immer daran denken, worauf Sie angewiesen sind, und es sich zur Gewohnheit machen, sie zu injizieren, wird Ihre Klasse natürlich lose miteinander verbunden.
- Abhängigkeitsisolation
- Isolieren Sie die Erstellung von Instanzvariablen anderer Klassen aus der Initialisierung von "self" und erstellen Sie sie in der Methode, die unabhängig in "self" definiert ist.
- Die Abhängigkeit wird deutlich und die Barriere für die Wiederverwendung wird gesenkt.
-
||=
Operator (verzögerte Instanzerstellung)
- Wenn eine andere Nachricht als "self" gesendet wird
- Entfernen Sie externe Abhängigkeiten und kapseln Sie sie in eine dedizierte Methode
- Die Methode wird unabhängig von externen Objekten und hängt von der Nachricht ab, die an "self" gesendet wird.
- Wenn die Nachricht Argumente anfordert
- Options-Hash empfangen
- Alle Abhängigkeiten von der Reihenfolge der Argumente werden entfernt.
- Der "Schlüssel" -Name im Hash wird zur expliziten Dokumentation für das Argument.
- Der Hash gibt "nil" für nicht vorhandene Schlüssel zurück, sodass Sie explizit einen Standardwert festlegen können.
-
||
Operator, fetch
Methode, merge
Methode
- Wenn die Reihenfolge der Argumente festgelegt ist (wenn die Methode, von der abhängig sein muss, extern ist usw.)
- Führen Sie eine Methode aus, um die externe Schnittstelle zu schließen.
--Erstellen Sie ein "Wrapper" -Modul (= "Fabrik").
- Ein Objekt, dessen Zweck es ist, andere Objekte zu erstellen
- Durch Aufrufen einer externen Methode innerhalb der Factory-Methode können Sie mehrere Abhängigkeiten von Argumenten fester Reihenfolge vermeiden.
--Die Fabrik soll nicht instanziiert werden.
--Factory wird voraussichtlich nicht in anderen Klassen enthalten sein.
3-3. Verwaltung der Abhängigkeitsrichtung
- Abhängigkeiten umkehren
- Auswahl der Abhängigkeitsrichtung
- "Hängen Sie davon ab, was von Ihnen selbst unverändert ist" = Drei Fakten, die die Grundlage des folgenden Konzepts bilden
- Einige Klassen haben variablere Anforderungen als andere
- Rahmenarbeit mit aktiver Entwicklung usw.
- Konkrete Klassen ändern sich eher als abstrakte Klassen
- Injektion von abhängigen Objekten usw.
- Die Abhängigkeit vom Abstrakten ist immer sicherer als die Abhängigkeit vom Konkreten.
- Das Ändern abhängiger Klassen von vielen Orten aus hat weitreichende Auswirkungen
- Vermeiden Sie stark abhängige Klassen
--Finden Sie die betreffende Abhängigkeit
- Wenn die konkrete Klasse viele Abhängigkeiten aufweist, sollten Sie einen mentalen Alarm auslösen.
――Der Schlüssel zur Wartung besteht darin, die Richtung der Abhängigkeit zu kontrollieren und sich auf eine Klasse zu verlassen, die sich weniger ändert als Sie.
Vom objektzentrierten Design zum nachrichtenzentrierten Design
4. Erstellen Sie eine flexible Schnittstelle
- Beim Design geht es nicht nur darum, was ein Objekt weiß (Objektverantwortung) oder wen es kennt (Objektabhängigkeiten).
--Wie die Objekte miteinander sprechen.
4-1. Grundlegendes zur Benutzeroberfläche
- Öffentliche Schnittstelle
- Extern exponierte Methoden
- Die Klasse implementiert Methoden, von denen einige von anderen Objekten verwendet werden sollen.
4-2. Definieren Sie die Schnittstelle
- Merkmale der öffentlichen Schnittstelle
- Klären Sie die Hauptverantwortlichkeiten der Klasse
- Wird voraussichtlich von außen ausgeführt
- Nicht aus einer Laune heraus geändert
- Sicher für andere, sich darauf zu verlassen
- Im Test vollständig dokumentiert
- Merkmale der privaten Schnittstelle
- Beteiligen Sie sich an Implementierungsdetails
- Es wird nicht erwartet, dass es von anderen Objekten stammt
- Kann aus irgendeinem Grund geändert werden
- Es ist gefährlich für andere, sich darauf zu verlassen
- Darf im Test nicht erwähnt werden
- Die öffentliche Schnittstelle ist ein Vertrag, in dem die Verantwortung der Klasse klar angegeben ist.
- Durch Markieren einer Methode als öffentlich oder privat wird dem Klassenbenutzer mitgeteilt, von welcher Methode er wahrscheinlich sicher abhängt.
4-3. Suchen Sie eine öffentliche Schnittstelle
-
Anwendungsdesign
-
"Domain-Objekt"
-
Eine persistente Klasse, die ein "Substantiv" darstellt, das sowohl "Daten" als auch "Verhalten" aufweist.
—— Große und sichtbare Objekte der realen Welt, die letztendlich in der Datenbank dargestellt werden.
-
Domänenobjekte spielen beim Entwerfen von Anwendungen keine zentrale Rolle.
-
Konzentrieren Sie sich auf die Nachrichten, die zwischen Objekten ausgetauscht werden, nicht auf die Objekte.
-
Sie sollten zuerst sowohl die "Objekte" als auch die "Nachrichten" herausfinden, die für Ihren Anwendungsfall erforderlich sind.
--Verwenden Sie ein Sequenzdiagramm
――Entdecken Sie den Nachrichtenaustausch (öffentliche Schnittstelle) zwischen Klassen und fragen Sie: "Sollte dieser Empfänger für die Beantwortung dieser Nachricht verantwortlich sein?"
--Klassen und wer und was sie wissen => Entscheide dich für eine Nachricht und wohin sie gesendet werden soll
-
"Ich weiß, dass ich diese Klasse brauche, aber was soll ich tun?" => "Ich muss diese Nachricht senden, aber wer sollte antworten?"
-
Fragen Sie den Empfänger "was", anstatt dem Absender "wie" zu sagen.
-
Übertragung der Verantwortung, zu wissen, wie andere Klassen
-
Die kleine öffentliche Schnittstelle bedeutet, dass es nur wenige Methoden gibt, die anderswo davon abhängen.
-
Verbesserte Codeflexibilität und Wartbarkeit.
-
Suche nach kontextueller Unabhängigkeit
-
Die beste Situation ist, dass das Objekt völlig unabhängig von seinem Kontext ist (so dass das Objekt in der Lage ist, auf Nachrichten anderer Klassen zu reagieren).
-
Konzentrieren Sie sich auf den Unterschied zwischen "was" und "wie"
-
Abhängige Objekte injizieren
-
Techniken für die Zusammenarbeit mit anderen, ohne zu wissen, wer sie sind
――Ich hoffe, dass Sie dem Empfänger der Nachricht vertrauen und sich angemessen verhalten.
-
Bedeutung des Vertrauens
-
"Ich weiß was ich will und ich weiß wie du es machst" => "Ich weiß was ich will und du Ich weiß, was zu tun ist "=>" Ich weiß, was ich will und ich glaube, Sie werden Ihren Teil dazu beitragen. "
――Dieses Vertrauen, loszulassen, ist der Schlüssel zu objektorientiertem Design
--Die Notwendigkeit neuer Objekte entdecken
- Wenn das Prinzip der Einzelverantwortung verletzt wird.
- Es sagt anderen Objekten, wie es sich verhält und erfordert eine große Menge an Kontext.
- Ein neues Objekt wurde entdeckt, weil es eine Nachricht an es senden musste
4-4. Schreiben Sie den Code, der die beste Seite (Schnittstelle) verfügbar macht.
――Die Schnittstelle definiert die Anwendung und bestimmt die Zukunft.
- Jedes Mal, wenn Sie eine Klasse erstellen, deklarieren Sie die Schnittstelle.
--Methoden in der "öffentlichen" Schnittstelle enthalten
- Identifizieren Sie sich explizit als öffentliche Schnittstelle
- "Was" ist mehr als "wie"
- Der Name ist unveränderlich, soweit wir uns vorstellen können
- Nehmen Sie einen Hash als optionales Argument
--Ruby public
, protected
, private
Schlüsselwörter
――Mit diesen Schlüsselwörtern können Sie die folgenden zwei Dinge vermitteln.
――Ich glaube, ich habe jetzt bessere Informationen als die Informationen, die "zukünftige" Programmierer haben.
――Ich glaube, wir müssen verhindern, dass zukünftige Programmierer versehentlich Methoden anwenden, die wir als instabil betrachten.
――Eine Reihe sehr talentierter Ruby-Programmierer wagt es, Schlüsselwörter wegzulassen.
-
Die Idee, dass Sie Schlüsselwörter verwenden können, um den Zugriff auf eine Methode einzuschränken, ist nur eine Illusion.
-
Wenn Sie eine öffentliche Schnittstelle erstellen, versuchen Sie, den Kontext zu minimieren, den die öffentliche Schnittstelle von anderen benötigt.
-
Lassen Sie den Absender der Nachricht das bekommen, was er will, ohne zu wissen, wie die Klasse dieses Verhalten implementiert.
-
Auch wenn die Person, die es zuerst geschrieben hat, die öffentliche Schnittstelle nicht definiert hat, erstellen Sie die öffentliche Schnittstelle selbst.
4-5 Demeter-Gesetz
- Eine Sammlung von Codierungsregeln für die lose Kopplung von Objekten.
- Dies bedeutet, dass die öffentliche Schnittstelle nicht genau identifiziert und definiert wurde.
――Es gibt Zeiten, in denen es keinen tatsächlichen Schaden gibt, selbst wenn Sie gegen das Gesetz verstoßen.
- "Reden wir nur mit unseren unmittelbaren Nachbarn"
- "Verwenden wir nur einen Punkt"
- Holen Sie sich entfernte Attribute durch ein Zwischenobjekt.
- Identifizieren Sie Zwischenobjekte explizit und ändern Sie sie nach Bedarf.
- Delegation verwenden.
--
delegate
Methode
―― Überdenken Sie die Nachrichtenkette basierend auf dem, was Sie suchen
――Sie müssen nicht wissen, wie.
- Wenn Sie zu einer nachrichtenbasierten Perspektive wechseln und eine Nachricht finden, wird diese Nachricht natürlich zur öffentlichen Schnittstelle eines Objekts.
――Die Nachricht selbst führt Sie zu dem Objekt.
5. Reduzieren Sie die Kosten durch Entenschreiben
――Was ist "Ententippen"?
- Öffentliche Schnittstelle, die nicht an eine bestimmte Klasse gebunden ist
- Genau wie Chamäleon. "Wenn ein Objekt wie eine Ente klingt und wie eine Ente geht, unabhängig von seiner Klasse, ist es eine Ente."
5-1. Ententyp verstehen
-
Einige Anwendungen definieren möglicherweise mehrere Schnittstellen, die mehrere Klassen umfassen.
――Das Wichtigste ist nicht, was das Objekt ist, sondern was es tut
-
Die Fähigkeit, Unklarheiten über eine Klasse von Objekten zu übersehen, erweist sich als selbstbewusster Designer.
-
Sie können ein Objekt so behandeln, als ob es durch sein Verhalten und nicht durch seine Klasse definiert wäre.
Polymorphismus
- Eine Vielzahl von Objekten bezieht sich auch auf die Fähigkeit, auf Nachrichten zu antworten.
- Eine Nachricht hat viele (Poly) Morphen.
5-2. Schreiben Sie Code, der Ente vertraut
-
Schwieriges Design
――Wissend, dass Sie einen Ententyp benötigen
--Um die Schnittstelle zu abstrahieren
-
Wie man eine versteckte Ente erkennt
- Case-Anweisung, die in der Klasse verzweigt
- kind_of? Und is_a?
3. responds_to?
- Fragen Sie, was das Argument dieser Methode will.
――Die Antwort auf diese Frage zeigt die zu sendende Nachricht. Aus dieser Nachricht wird der zugrunde liegende Ententyp definiert.
- Schließen Sie keine unnötigen Abhängigkeiten ein, die Sie steuern, anstatt anderen Objekten zu vertrauen.
- Vertraue der Ente.
- Sobald Sie den Ententyp kennen, definieren Sie die Schnittstelle, implementieren Sie sie dort, wo Sie sie benötigen, und vertrauen Sie darauf, dass sie sich korrekt verhält.
--Dokumentieren Sie den Ententyp.
- Wenn Sie einen Ententyp erstellen, müssen Sie dessen öffentliche Schnittstelle dokumentieren und testen.
- Code zwischen Ente teilen.
- Wenn Sie eine gemeinsame Methode definieren, teilen Sie nur die Schnittstelle, nicht die Implementierung.
- Oft müssen Sie auch etwas Verhalten teilen.
--Wählen Sie eine Ente mit Bedacht aus
- Verstehen Sie, dass, wenn die zugrunde liegende Ente eine Änderung der grundlegenden Ruby-Klassen erfordert, Risiken und Kompromisse bestehen und der Zweck des Designs darin besteht, die Kosten zu senken.
5-3 Überwinde die Angst vor dem Tippen von Enten
-
Entwertung des Ententyps durch statische Eingabe
-
Vergleich der dynamischen und statischen Typisierung
--Statische Eingabe
-
Der Compiler findet zur Kompilierungszeit Typfehler. <=> Wenn der Compiler nicht nach Typen sucht, treten Laufzeitfehler auf
-
Die visualisierten Typinformationen dienen auch als Dokument. Ohne den Typ <=> kann der Programmierer den Code nicht verstehen. Der Programmierer kann seinen Typ nicht aus dem Kontext des Objekts ableiten
-
Kompilierter Code ist optimiert und wird schnell ausgeführt. <=> Ohne eine Reihe von Optimierungen wird Ihre Anwendung zu langsam ausgeführt
-
Dynamische Eingabe
-
Der Code wird sequentiell ausgeführt und dynamisch geladen. Daher gibt es keinen Kompilierungs- / Erstellungszyklus. <=> Es ist sicherer, keinen Kompilierungs- / Erstellungszyklus für die gesamte Anwendungsentwicklung zu haben
-
Der Quellcode enthält keine expliziten Typinformationen. <=> Für den Programmierer ist es einfacher zu verstehen, wenn die Typdeklaration nicht im Code enthalten ist. Der Typ des Objekts kann aus diesem Kontext abgeleitet werden.
-
Einfachere Metaprogrammierung <=> Metaprogrammierung ist eine wünschenswerte Sprachfunktion
-
Es ist die eigene Intelligenz des Programmierers, um Tippfehler zu vermeiden. Die Idee, dass statisches Tippen es sicher macht, ist eine Illusion.
――Die Güte des Codes ist schließlich die Güte des Tests.
--Duck Typing basiert auf dynamischer Typisierung.
6. Erwerben Sie Verhalten durch Vererbung
6-1. Grundlegendes zur Klassenvererbung
- Vererbung ist der Mechanismus der "automatischen Nachrichtendelegierung"
6-2 Geben Sie an, wo die Vererbung verwendet werden soll
- Sie können Unterklassen finden, genau wie Sie es getan haben, als Sie einen Ententyp gefunden haben.
--Wenn Anweisung, Typ, Kategorie usw. "Attribute mit eigener Klassifizierung" bestätigen.
--bad: "Ich weiß, wer du bist, weil ich weiß, was du tust" => Zeigt die Existenz einer Unterklasse an.
- "Einzelvererbung". Unterklassen können nur eine übergeordnete Oberklasse haben.
- Unterklassen sind "spezialisierte" Oberklassen.
- Unterklassen haben alle öffentlichen Schnittstellen von Oberklassen.
6-3 Vererbung nicht ordnungsgemäß anwenden
- Das Senden von Super erbt unnötiges, völlig bedeutungsloses Verhalten.
6-4. Finden Sie die Zusammenfassung
- Das modellierte Objekt hat eine "Generalisierungs-Spezialisierungs-Beziehung".
- Verwenden Sie die richtige Codierungstechnik
- Erstelle eine abstrakte Oberklasse
- Eine Oberklasse ist kein vollständiges Objekt für sich.
――Es ist fast undenkbar, eine neue Nachricht an die Superklasse zu senden.
- Es gibt auch objektorientierte Programmiersprachen mit einer Syntax, die eine Klasse explizit als abstrakt deklariert, z. B. das Java-Schlüsselwort "abstract".
- Ruby hat solche Schlüsselwörter nicht, weil sie anderen vertrauen.
- Es gibt abstrakte Klassen für zu erstellende Unterklassen, und dies ist ihr einziger Zweck.
- Geben Sie einen gemeinsamen Speicherort für Verhaltensweisen an, die von Unterklassen gemeinsam genutzt werden.
- Es ist nicht sinnvoll, eine abstrakte Oberklasse mit nur einer Unterklasse zu erstellen.
- Der einfachste Weg, die richtige Zusammenfassung zu identifizieren, besteht darin, dass mindestens drei konkrete Klassen existieren.
-Fördern Sie abstraktes Verhalten
- Beim Refactoring in eine neue Vererbungshierarchie sollte der Code so strukturiert sein, dass die Zusammenfassung gefördert werden kann, nicht die konkrete.
- Separate Zusammenfassung von Beton.
--Verwenden Sie das Muster der Vorlagenmethode.
- Eine Technik, die die Grundstruktur innerhalb einer Oberklasse definiert und eine Nachricht für unterklassenspezifische Beiträge sendet.
- Superklassen stellen Unterklassen eine Struktur zur Verfügung (allgemeiner Algorithmus).
- Für alle Objekte verwenden einige Methoden denselben Anfangswert und einige Methoden unterschiedliche Anfangswerte.
- Stellen Sie sicher, dass jede Klasse, die das Muster der Vorlagenmethode verwendet, für jede gesendete Nachricht eine Implementierung hat.
- Die Anforderungen an Vorlagenmethoden werden immer dokumentiert, indem übereinstimmende Methoden implementiert werden, die nützliche Fehler verursachen.
6-5. Verwalten Sie den Konnektivitätsgrad zwischen Oberklassen und Unterklassen
- Die eng gekoppelten Klassen stehen in engem Kontakt miteinander, so dass es unmöglich ist, sie unabhängig voneinander zu ändern.
- Wenn eine Unterklasse "Super" sendet, ist dies eine Erklärung, dass sie den Algorithmus der Superklasse effektiv kennt und von diesem Wissen "abhängig" ist.
--Verwenden Sie Hook-Nachrichten, um Unterklassen lose zu koppeln.
- Anstatt Sie zu bitten, ein "Super" zu senden, lassen Sie die Superklasse stattdessen eine "Hook" -Nachricht senden.
- Durch die Verwendung der Hook-Methode kann der Erbe die Superklasse spezialisieren, ohne die Übertragung von "Super" zu erzwingen.
7. Teilen Sie das Rollenverhalten in Modulen
7-1. Rollen verstehen
-
Wenn ursprünglich nicht verwandte Objekte eine gemeinsame Rolle übernehmen, werden die Objekte miteinander verbunden. Der Ententyp ist eine Rolle.
-
Die Methode, einen Namen zu vergeben und eine Gruppe von Methoden zu definieren, wird als "Modul" bezeichnet.
-
Es ist eine perfekte Möglichkeit für Objekte verschiedener Klassen, eine gemeinsame Rolle mit Code zu spielen, der an einer Stelle definiert ist.
-
Der Satz von Nachrichten, auf die ein Objekt antworten kann, umfasst die folgenden vier Arten von Nachrichten.
--Nachrichten, die Sie implementieren
-
Nachrichten, die von allen Objekten in der Hierarchie über sich selbst implementiert wurden
-
Nachrichten, die zu sich selbst hinzugefügt und in allen Modulen implementiert wurden
-
Nachrichten, die in allen Modulen implementiert sind, die Objekten in der Hierarchie über sich selbst hinzugefügt wurden
-
Objekte sollten sich selbst verwalten
――Sie sollten Ihr eigenes Verhalten haben. Vermeiden Sie unnötige Abhängigkeiten.
-
Abhängige Objekte werden ausgeblendet, indem sie bei der Initialisierung eingefügt werden.
-
Durch das Erstellen eines Moduls können andere Objekte dieses Modul verwenden, um Rollen zu übernehmen, ohne Code zu duplizieren.
-
Wenn mehrere Module in einer Klasse enthalten sind, steht die Methode des zuletzt enthaltenen Moduls am Anfang des Methodensuchpfads.
-
Sie können auch nur einem Objekt Modulmethoden hinzufügen, indem Sie das Schlüsselwort Ruby extens
verwenden.
--extend
fügt das Verhalten des Moduls direkt zum Objekt hinzu.
--extend
die Klasse in einem Modul
-
Eine Klassenmethode wird "zu dieser Klasse" hinzugefügt.
--extend
eine Instanz der Klasse
-
Eine Instanzmethode wird "zu dieser Instanz" hinzugefügt.
7-2. Schreiben Sie vererbbaren Code
- Ein Muster, in dem ein Objekt Variablennamen wie "Typ" und "Kategorie" verwendet, um zu bestimmen, welche Nachricht an sich selbst gesendet werden soll.
- Allgemeiner Code sollte in eine abstrakte Oberklasse eingefügt werden, und Unterklassen sollten verwendet werden, um verschiedene Typen zu erstellen.
- Ein Muster, in dem das Objekt entscheidet, welche Nachricht gesendet werden soll, nachdem die Klasse des Objekts überprüft wurde, das die Nachricht empfängt.
-
Das Objekt des Empfängers sollte eine Schnittstelle vom Typ Ente implementieren.
-
Ententypen teilen manchmal das Verhalten. Fügen Sie in diesem Fall allgemeinen Code in ein Modul ein und fügen Sie dieses Modul in jede Klasse oder jedes Objekt ein, um die Rolle zu übernehmen.
-
In der abstrakten Oberklasse dürfen keine Unterklassen vorhanden sein, die keinen Code verwenden.
――Wenn Sie die Zusammenfassung nicht korrekt auf eine eingrenzen können oder wenn kein allgemeiner Code abstrahiert werden kann, kann die Vererbung das Entwurfsproblem nicht lösen.
-
Unterklassen versprechen, Superklassen zu ersetzen.
-
Es ist nicht zulässig, dass andere Objekte ihren Typ identifizieren und entscheiden, was mit ihnen zu tun ist oder was zu erwarten ist.
Riskovs Ersatzprinzip
- "Damit das System fehlerfrei ist, muss der abgeleitete Typ durch den Supertyp ersetzt werden können."
- Mit anderen Worten, wie Ruby, "sollten sich Objekte so verhalten, wie sie es behaupten."
--Verwenden Sie das Muster der Vorlagenmethode
-
Bei der konkreten Vererbung der Abstraktion erfolgt die Spezialisierung durch Überschreiben der Vorlagenmethode.
--Mit der Template-Methode müssen Sie klar entscheiden, was sich ändert und was nicht.
-
Vermeiden Sie das Schreiben von Code, der auf der erbenden Seite super aufruft.
-
Verwenden Sie stattdessen Hook-Nachrichten.
-
Sie können dem Algorithmus beitreten, während Sie von der Verantwortung befreit sind, den Algorithmus der abstrakten Klasse zu kennen.
8. Kombinieren Sie Objekte in der Komposition
8-1. Stellen Sie das Fahrrad aus den Teilen zusammen
- Mit der Beziehung "Fahrrad hat Teile" = Zusammensetzung
--Erstellen Sie eine abstrakte Teileklasse.
8-2. Teile-Objekt erstellen
- Machen Sie einen Teil. Teile hat mehrere Teilobjekte.
- Gruppieren Sie einzelne Teilobjekte zu Teilobjekten.
- Jedes Array von Part-Objekten ist ein Objekt, das die Rolle von Part spielt.
- Keine Instanz der Part-Klasse.
- Es ist nicht der Typ der Teileklasse.
8-3. Herstellungsteile
-"Fabrik"
- Ein Objekt, das andere Objekte erstellt.
- Rubys OpenStruct-Klasse
- Eine bequeme Möglichkeit, mehrere Attribute zu einem Objekt zu kombinieren.
- Struct
- Es ist erforderlich, die Reihenfolge anzugeben und die Argumente zum Zeitpunkt der Initialisierung zu übergeben.
- OpenStruct
- Nehmen Sie bei der Initialisierung einen Hash und extrahieren Sie Attribute daraus.
8-4. Zusammengesetztes Fahrrad
- Teile spielen die Rolle von Teilen
--OpenStruct übernimmt die Rolle des Teils, der Name, Beschreibung und Bedarfsersatz implementiert.
Aggregation - eine besondere Zusammensetzung
――Was ist Komposition?
- Zwei Objekte haben eine "has-a" -Beziehung
- Dinge, die das enthaltene Objekt nicht unabhängig vom enthaltenen Objekt existieren kann
――Beispiel: Ein Gericht hat eine Vorspeise, aber sobald das Gericht gegessen ist, verschwindet auch die Vorspeise.
――Was ist Aggregation?
- Die Existenz des enthaltenen Objekts ist unabhängig.
--Beispiel: Auch wenn die Universität verschwindet und die Fakultät verschwindet, existieren die Professoren immer noch.
8-5 Auswahlmöglichkeiten für Zusammensetzung und Vererbung
-
Klassenvererbung
-
Anstatt die Kosten für die Organisation der Objekte in einer hierarchischen Struktur zu bezahlen, fallen für die Nachricht keine ungewöhnlichen Kosten an.
--Komposition
-
Objekte können jetzt strukturell unabhängig existieren, jedoch auf Kosten einer expliziten Nachrichtendelegierung.
-
Kompositionen haben weitaus weniger Abhängigkeiten als Vererbungen. Priorisieren Sie daher Kompositionen.
--Vorteile der Vererbung
--WAHR.
--Open / Closed (Offen für Erweiterungen, geschlossen für Korrekturen)
- Vererbungskosten
- Wenn Sie versehentlich die Vererbung wählen, müssen Sie Ihren Code duplizieren oder neu konfigurieren.
- Kann von anderen Programmierern für völlig unerwartete Zwecke verwendet werden.
--Vorteile der Zusammensetzung
-
Da es strukturell unabhängig ist, ist es sehr benutzerfreundlich und kann auch in neuen Kontexten, die nicht erwartet wurden, problemlos verwendet werden.
――Es eignet sich sehr gut zum Definieren der Regeln für das Zusammensetzen eines aus Teilen bestehenden Objekts.
-
Zusammensetzungskosten
-
Hängt von vielen Teilen ab.
――Selbst wenn die einzelnen Teile klein und leicht zu verstehen sind, ist die Gesamtbedienung der Kombination nicht leicht zu verstehen.
-
Opfern Sie die automatische Delegierung von Nachrichten.
-
Sie müssen explizit wissen, welche Nachricht an wen delegiert werden soll.
――Es hilft nicht so sehr bei dem Problem, einen Code mit fast denselben Teilen zu bilden.
--is-a Vererbung für Beziehungen verwenden
- Vererbung ist eine Spezialisierung.
- Die Vererbung eignet sich am besten zum Hinzufügen von Funktionen zu einer vorhandenen Klasse, während der größte Teil des alten Codes verwendet wird und eine relativ kleine Menge neuen Codes hinzugefügt wird.
--Hehaves-like-a Verwenden Sie den Ententyp für Beziehungen
- Wenn ein Objekt eine Rolle hat, diese Rolle jedoch nicht in der Hauptverantwortung des Objekts liegt.
- Wenn nicht verwandte Objekte den Wunsch teilen, dieselbe Rolle zu spielen.
- In Ruby-Modulen wird allgemeines Verhalten definiert, sodass Objekte Rollen übernehmen können, ohne Code zu duplizieren.
--has-a Komposition für Beziehungen verwenden
-Wenn viele Objekte mehrere Teile enthalten und die Summe dieser Objekte die Summe dieser Teile überschreitet.
-
Je mehr Teile ein Objekt hat, desto wahrscheinlicher ist es, dass es in einer Komposition modelliert wird.
-
Zu lernen, Techniken wie Komposition, Vererbung nach Klassen und Austausch von Verhalten mithilfe von Modulen richtig anzuwenden, ist eine Frage der Erfahrung und des Urteilsvermögens.
Testdesign
9. Entwerfen Sie kostengünstige Tests
――Drei Fähigkeiten sind für das Üben von modifizierbarem Code unverzichtbar.
- Verständnis von objektorientiertem Design.
- Gut im Code-Refactoring.
――Refactoring bezieht sich auf die Arbeit zur Verbesserung der internen Struktur unter Beibehaltung des externen Verhaltens der Software.
- Fähigkeit, hochwertige Tests zu schreiben.
9-1. Absichtliche Prüfung
-
Testabsicht
-
Finde einen Fehler
-
Es wird eine Spezifikation
-
Verzögerungsentwurfsentscheidungen
--Der Test zeigt, dass sich die Schnittstelle weiterhin korrekt verhält, sodass Sie den Test nicht ändern müssen, wenn Sie den zugrunde liegenden Code ändern.
-
Unterstützung der Abstraktion
-
Konstruktionsfehler erklären
-
Schreiben Sie weniger Tests
-
Sie sollten die stabilste, von der öffentlichen Schnittstelle definierte Nachricht schreiben.
9-2. Eingehende Nachrichten testen
--Entfernen Sie Tests für eingehende Nachrichten, die nicht abhängig sind.
- Machen Sie einen Test doppelt.
- Ein gefälschtes Objekt, das die Rolle übernimmt. Eine stilisierte Instanz des Rollenträgers. Wird nur zum Testen verwendet.
- Verdoppeln Sie die Methode. Implementieren Sie also eine Methode, die eine vorab ausgefüllte Antwort zurückgibt.
9-3. Testen Sie private Methoden
-
Private Methoden sind redundant und instabil (variabel), und die Wartungszeit erhöht sich. Ignorieren Sie sie daher.
-
Erstellen Sie nicht zuerst die private Methode selbst.
――Ein Objekt mit vielen privaten Methoden riecht nach einem Design, das zu viel Verantwortung trägt.
-
Überlegen Sie, diese Objekte in neue zu schneiden.
-
"Schreiben Sie niemals private Methoden. Wenn Sie dies tun, testen Sie sie niemals, es sei denn, dies ist natürlich sinnvoll."
9-4. Ausgehende Nachrichten testen
-
Ob die ausgehende Nachricht eine "Abfrage" oder ein "Befehl" ist.
-
Abfragenachrichten sind nur für die Objekte von Bedeutung, die sie senden.
--Befehlsnachrichten haben sichtbare Auswirkungen auf andere Objekte in der Anwendung.
-
Der Test sollte die an sich selbst gesendete Nachricht ignorieren.
-
Eine ausgehende Abfragenachricht sollte ebenfalls ignoriert werden.
-
Wenn Sie abhängige Objekte im Voraus injiziert haben, können Sie sie einfach durch Mock ersetzen.
-
Indem Sie Erwartungen an das Modell setzen, können Sie nachweisen, dass das zu testende Objekt seine Verantwortung erfüllt, ohne Aussagen zu duplizieren, die irgendwo anders hingehören.
9-5 Testen Sie den Ententyp
-
Wenn Sie auf Code stoßen, der Anti-Patterns verwendet, aber keine Tests enthält, sollten Sie ihn überarbeiten, bevor Sie die Tests für ein besseres Design schreiben.
-
Der Rollentest sollte nur einmal geschrieben und von allen Trägern geteilt werden.
--Minitest unterstützt die Testfreigabe mit Ruby-Modulen.
-
Schneiden Sie das Verhalten in Module aus.
-
Wenn Sie den Test doppelt wie jeden anderen Träger der Rolle behandeln und seine Richtigkeit im Test nachweisen, können Sie die Zerbrechlichkeit des Tests und des Stubs vermeiden, ohne sich um die Auswirkungen sorgen zu müssen.
-
Der Wunsch, Ententyp-Tests durchzuführen, hat die Notwendigkeit von gemeinsam nutzbaren Tests für Rollen geschaffen. Und sobald Sie eine Perspektive haben, die auf dieser Rolle basiert, können Sie sie in einer Vielzahl von Situationen verwenden. Aus Sicht des zu testenden Objekts sind alle anderen Objekte Rollen. Wenn Sie das Objekt dann so behandeln, als wäre es eine Darstellung dieser Rolle, wird die Bindung gelockert und die Flexibilität erhöht. Dies gilt sowohl für Anwendungen als auch für Tests.
9-6 Testen Sie den geerbten Code
--Riskovs Ersatzprinzip
-
Der abgeleitete Typ sollte durch seinen überlegenen Typ ersetzt werden können.
-
Der einfachste Weg, um zu beweisen, dass Sie dem Ersetzungsprinzip von Riskov folgen, besteht darin, einen Test (der Schnittstelle) zu schreiben, der in diesem gemeinsamen Vertrag enthalten ist, und den Test aller Objekte (in den Test der konkreten Klasse) einzubeziehen. ..
--Schreiben Sie einen Verhaltenstest, der für Unterklassen gilt.
-
Indem Sie die Schnittstelle der abstrakten Klasse testen und das Verhalten der Unterklassen testen, können Sie sicher sein, dass die Unterklassen nicht außerhalb des Standards liegen und neue Mitglieder Unterklassen ganz sicher erstellen können. Neue Programmierer müssen nicht nach Superklassen suchen, um ihre Anforderungen zu erfüllen. Fügen Sie beim Zeichnen einer neuen Unterklasse einfach diese Tests hinzu.
-
Das Erstellen einer Instanz einer abstrakten Klasse ist entweder schwierig, ziemlich schwierig oder unmöglich.
--Wenn Sie ein unterklassenspezifisches Teil testen, ist es wichtig, kein Wissen der Oberklasse in den Test einzubetten.
-
Wenn die Oberklasse Vorlagenmethoden verwendet, um eine konkrete Spezialisierung zu erreichen, kann sie das Verhalten von Unterklassen stubben.
-
Die Idee, eine Unterklasse zum Vorbereiten eines Stubs zu erstellen, ist in vielen Situationen nützlich. Sie können diese Technik in jedem Test verwenden, solange Sie nicht gegen das Liskov-Ersetzungsprinzip verstoßen.
-
Sorgfältig geschriebenes Testen der Vererbungsstruktur ist einfach. Schreiben Sie einen gemeinsam nutzbaren Test für die gesamte Schnittstelle und den anderen für die Verantwortlichkeiten der Unterklassen.
――Geteilte Verantwortlichkeiten nacheinander.
-
Achten Sie beim Testen von Unterklassenspezialisierungen darauf, dass Sie Ihr Wissen über Oberklassen nicht an die Unterklassentests weitergeben.
――Es ist schwierig, die abstrakte Superklasse zu testen.
--Wenn Sie das Ersetzungsprinzip von Riskov verwenden und Nur-Test-Unterklassen erstellen, wenden Sie den Verantwortlichkeitstest der Unterklasse auch auf diese Unterklassen an.
-
Der beste Test ist lose mit dem Code von Interesse verbunden, testet alles nur einmal und führt ihn an der richtigen Stelle durch.