Ich programmiere seit einiger Zeit in prozeduralen Sprachen und meine erste Reaktion auf ein Problem besteht darin, es in Aufgaben zu zerlegen, anstatt die verschiedenen Entitäten (Objekte), die existieren, und ihre Beziehungen zu berücksichtigen.
Ich habe einen Universitätskurs in OOP absolviert und verstehe die Grundlagen von Kapselung, Datenabstraktion, Polymorphismus, Modularität und Vererbung.
Ich lese /programming/2688910/learning-to-think-in-the-object-oriented-way und /programming/1157847/learning-object-oriented-thinking , und wir werden uns einige der Bücher ansehen, auf die in diesen Antworten verwiesen wird.
Ich denke, dass einige meiner mittleren bis großen Projekte von der effektiven Nutzung von OOP profitieren werden, aber als Anfänger möchte ich zeitaufwendige, häufige Fehler vermeiden.
Welche Fallstricke haben Sie aufgrund Ihrer Erfahrungen und welche Umgehungsmöglichkeiten bieten sich an? Wenn Sie erklären könnten, warum es sich um Fallstricke handelt und wie effektiv Ihr Vorschlag bei der Lösung des Problems ist, wären Sie dankbar.
Ich denke an etwas wie "Ist es üblich, eine ganze Reihe von Beobachter- und Modifikatormethoden zu haben und private Variablen zu verwenden, oder gibt es Techniken, um diese zu konsolidieren / zu reduzieren?"
Ich mache mir keine Sorgen, C ++ als reine OO-Sprache zu verwenden, wenn es gute Gründe gibt, Methoden zu mischen. (Erinnert an die Gründe für den sparsamen Einsatz von GOTOs.)
Vielen Dank!
quelle
Antworten:
Eine große Sache, die ich gelernt habe, ist das Entwerfen von Klassen von außen nach innen. Entwerfen Sie die Benutzeroberfläche, bevor Sie überhaupt über die Implementierung nachdenken. Dies macht die Klasse für Ihre Benutzer (die die Klasse verwenden) viel intuitiver als das Schreiben der zugrunde liegenden Algorithmen und das Erstellen der Klasse sowie das Schreiben neuer Funktionen für öffentliche Mitglieder, wenn diese benötigt werden.
quelle
Nun, das erste ist die Gefahr, zu viele Informationen preiszugeben. Die Standardeinstellung sollte
private
nicht seinpublic
.Danach kommen zu viele Getter / Setter. Angenommen, ich habe ein Datenelement. Brauche ich diese Daten wirklich in einer anderen Klasse? Ok, mach einen Getter. Muss ich diese Daten wirklich während der Lebensdauer des Objekts ändern? Dann mach einen Setter.
Die meisten unerfahrenen Programmierer haben die Standardeinstellung, für jedes Datenelement einen Getter / Setter zu erstellen. Dies wirft Schnittstellen auf und ist oft eine schlechte Designauswahl.
quelle
Als ich diesen Abgrund überquerte, entschied ich mich für den folgenden Ansatz:
0) Ich habe langsam angefangen, mit kleinen / mittleren prozeduralen Apps und ohne wichtige Aufgaben.
1) Eine einfache Zuordnung im ersten Durchgang, wie ich das Programm von Grund auf im OO-Stil schreiben würde - was für mich damals am wichtigsten war und das ist subjektiv -, bestand darin, alle Basisklassen herauszufinden. Mein Ziel war es, so viel wie möglich in den Basisklassen zu kapseln. Reine virtuelle Methoden für alles Mögliche in den Basisklassen.
2) Im nächsten Schritt wurden die Ableitungen erstellt.
3) Der letzte Schritt war - im ursprünglichen Verfahrenscode die Datenstrukturen vom Beobachter- / Modifikatorcode zu trennen. Verwenden Sie dann das Ausblenden von Daten, und ordnen Sie alle allgemeinen Daten den Basisklassen zu. In den Unterklassen wurden die Daten abgelegt, die im gesamten Programm nicht üblich waren. Und die gleiche Behandlung für den prozeduralen Beobachter / Modifizierer-Code - die gesamte Logik, die überall verwendet wird, floss in die Basisklassen. Die Logik zum Anzeigen / Ändern, die nur auf eine Teilmenge der Daten angewendet wurde, wurde in die abgeleiteten Klassen übernommen.
Dies ist subjektiv, aber es ist SCHNELL, wenn Sie den Verfahrenscode und die Datenstrukturen gut kennen. Ein FAIL in einer Codeüberprüfung liegt vor, wenn ein Teil der Daten oder der Logik nicht in den Basisklassen enthalten ist, sondern überall verwendet wird.
quelle
Werfen Sie einen Blick auf andere erfolgreiche Projekte, die OOP verwenden, um ein Gefühl für guten Stil zu bekommen. Ich empfehle, mir Qt anzuschauen, ein Projekt, an dem ich mich immer orientiere, wenn ich meine eigenen Designentscheidungen treffe.
quelle
Je nachdem, mit wem Sie sprechen, sollten alle Daten in OOP privat oder geschützt sein und nur über Accessoren und Mutatoren verfügbar sein. Im Allgemeinen halte ich dies für eine gute Praxis, aber es gibt Fälle, in denen ich von dieser Norm abweiche. Wenn Sie beispielsweise eine Klasse haben (in Java beispielsweise), deren einziger Zweck darin besteht, einige Daten zu einer logischen Einheit zusammenzufassen, ist es sinnvoll, die Felder öffentlich zu lassen. Wenn es sich um eine unveränderliche Kapsel handelt, markieren Sie sie einfach als endgültig und initialisieren Sie sie im Konstruktor. Dies reduziert die Klasse (in diesem Fall) auf etwas mehr als eine Struktur (in C ++ sollten Sie dies eigentlich eine Struktur nennen. Funktioniert genau wie eine Klasse, aber die Standardsichtbarkeit ist öffentlich und Ihre Absicht ist klarer), aber Ich denke, Sie werden feststellen, dass die Verwendung in diesen Fällen viel komfortabler ist.
Eine Sache, die Sie definitiv nicht tun möchten, ist, ein Feld zu haben, das auf Konsistenz im Mutator überprüft werden muss, und es öffentlich zu lassen.
quelle
struct
s deklarieren - es macht keinen semantischen Unterschied, aber es verdeutlicht die Absicht und lässt ihre Verwendung natürlicher erscheinen, insbesondere für C-Programmierer.Kent Becks Buch Implementation Patterns bietet eine hervorragende Grundlage für den Einsatz objektorientierter Mechanismen, nicht für den Missbrauch.
quelle
Ich mache mir keine Sorgen, C ++ als reine OO-Sprache zu verwenden, wenn es gute Gründe gibt, Methoden zu mischen. (Erinnert an die Gründe für den sparsamen Einsatz von GOTOs.)
Ich dachte nicht wirklich, dass ich viel zu bieten hätte, bis ich dieses Stück gesehen habe. Ich muss dem Gefühl nicht zustimmen. OOP ist nur eines der Paradigmen, die in C ++ verwendet werden können und sollten. Ehrlich gesagt, meiner Meinung nach ist es nicht eines der stärksten Merkmale.
Aus Sicht von OO denke ich, dass C ++ tatsächlich ein bisschen zu kurz kommt. Die Idee, nicht-virtuelle Funktionen zu haben, spricht in dieser Hinsicht dagegen. Ich habe mit denen gestritten, die mit mir nicht übereinstimmen, aber nicht-virtuelle Mitglieder passen einfach nicht zum Paradigma, was mich betrifft. Polymorphismus ist eine Schlüsselkomponente von OO, und Klassen mit nicht virtuellen Funktionen sind im Sinne von OO nicht polymorph. Als OO-Sprache denke ich, dass C ++ im Vergleich zu Sprachen wie Java oder Objective-C eher schwach ist.
Generische Programmierung auf der anderen Seite hat C ++ diese ziemlich gut. Ich habe gehört, dass es auch dafür bessere Sprachen gibt, aber die Kombination von Objekten und generischen Funktionen ist etwas ziemlich Mächtiges und Ausdrucksstarkes. Außerdem kann es sowohl in der Programmierzeit als auch in der Verarbeitungszeit verdammt schnell sein. Es ist wirklich in diesem Bereich, dass ich denke, C ++ scheint, obwohl es zugegebenermaßen besser sein könnte (Sprachunterstützung für Konzepte zum Beispiel). Jemand, der denkt, dass er sich an das OO-Paradigma halten und die anderen in der Reihenfolge der goto-Anweisung in Stufen der Unmoral behandeln sollte, verpasst es wirklich, wenn er sich dieses Paradigma nicht ansieht.
Die Metaprogrammierungskapazität von Vorlagen ist ebenfalls beeindruckend. Schauen Sie sich zum Beispiel die Boost.Units-Bibliothek an. Diese Bibliothek bietet Unterstützung für Maßgrößen. Ich habe diese Bibliothek in dem Ingenieurbüro, für das ich derzeit arbeite, ausgiebig genutzt. Es bietet nur eine viel schnellere Rückmeldung für einen Aspekt des möglichen Programmierers oder sogar einen Spezifikationsfehler. Es ist unmöglich, ein Programm zu kompilieren, das eine Formel verwendet, bei der beide Seiten des Operators '=' ohne explizite Umwandlung nicht dimensional äquivalent sind. Ich persönlich habe keine Erfahrung mit einer anderen Sprache, in der dies möglich ist, und schon gar nicht mit einer, die auch die Leistung und Geschwindigkeit von C ++ hat.
Metaprogrammierung ist ein rein funktionales Paradigma.
Also wirklich, ich denke, Sie betreten C ++ bereits mit einigen unglücklichen Missverständnissen. Die anderen Paradigmen neben OO sind nicht zu vermeiden, sie sind zu GEHEBELN. Verwenden Sie das Paradigma, das für den Aspekt des Problems, an dem Sie arbeiten, natürlich ist. Erzwingen Sie keine Objekte auf etwas, das im Wesentlichen kein objektanfälliges Problem ist. Für mich ist OO nicht einmal die halbe Wahrheit für C ++.
quelle
Ich wollte eine Antwort auf diese Frage akzeptieren, konnte mich aber nicht für eine Antwort entscheiden, um das Häkchen zu setzen. Als solche habe ich die Originalautoren aufgewertet und diese als zusammenfassende Antwort erstellt. Vielen Dank an alle, die sich ein paar Minuten Zeit genommen haben. Ich habe festgestellt, dass der von Ihnen gewährte Einblick mir eine gute Richtung und ein wenig die Gewissheit gab, dass ich nicht von der Stange bin.
@nightcracker
Ich hatte das Gefühl, dieses Problem in der Vergangenheit in Aktion beobachtet zu haben. Ihre Kommentare haben mich auch daran erinnert, dass ich durch das Ausblenden der zugrunde liegenden Variablen und ihrer Implementierung die Möglichkeit habe, ihre Implementierung zu ändern, ohne irgendetwas zu zerstören, das von ihnen abhängig ist.
Dominic Gurto
Ich fand, dass Dominics Kommentar ein großartiges Ideal war, um danach zu streben, aber ich denke, dass Gens Kommentar wirklich die Realität der Situation trifft. Bisher habe ich das in Aktion gesehen ... und fühle mich ein bisschen besser, dass es nicht ungewöhnlich ist. Ich denke, wenn ich als Programmierer reife, neige ich zu vollständigeren Designs, aber im Moment leide ich immer noch darunter, mich einzumischen und Code zu schreiben.
wantTheBest
Das macht sehr viel Sinn ... Ich mochte die Idee, die Dinge am Laufen zu halten, aber einige der unkritischen Dinge mit Klassen zu überarbeiten.
jpm
Ich habe seit einiger Zeit gewusst, dass dies eine der Stärken der Kapselung von Daten ist.
Verrückter Eddie
Ich habe Crazy Eddies Antwort ursprünglich sehr vermisst, weil ich einige der genannten Themen nicht gelesen hatte ... wie Metaprogrammierung. Ich denke, die großartige Botschaft in CEs Post war, dass C ++ eine solche Mischung aus Fähigkeiten und Stilen ist, dass jeder sein bestes Potenzial ausschöpfen sollte ... auch zwingend, wenn das Sinn macht.
Nochmals vielen Dank an alle, die geantwortet haben!
quelle
Die größte Gefahr ist der Glaube, dass OOP eine Silberkugel oder das "perfekte Paradigma" ist.
quelle