Denken Sie, dass objektorientierte Programmierung eine Lösung für Komplexität ist? Warum? Dieses Thema mag ein bisschen umstritten sein, aber meine Absichten, die Antwort von Warum von den Experten hier zu erfahren!
18
Denken Sie, dass objektorientierte Programmierung eine Lösung für Komplexität ist? Warum? Dieses Thema mag ein bisschen umstritten sein, aber meine Absichten, die Antwort von Warum von den Experten hier zu erfahren!
Antworten:
Es gibt keine Lösung für die Komplexität.
In "The Mythical Man-Month" diskutiert Fred Brooks den Unterschied zwischen zufälliger und wesentlicher Komplexität in der Programmierung. Die zufällige Komplexität wird durch unsere Tools und Methoden verursacht, z. B. durch das Schreiben und Testen von zusätzlichem Code in einer Sprache, da wir unsere Ideen nicht direkt ausdrücken können. Neue Methoden und Techniken können die zufällige Komplexität verringern. Ich kann Programme schneller und besser schreiben als vor 25 Jahren, weil ich bessere Sprachen und Werkzeuge habe.
Wesentliche Komplexität ergibt sich aus der Tatsache, dass das, was wir mit der Programmierung zu tun versuchen, von Natur aus kompliziert ist und dass es eine nicht reduzierbare Komplexität gibt. "Wesentlich" bedeutet in diesem Zusammenhang "auf das Wesentliche bezogen" und nicht "sehr notwendig".
Daher behauptete er, dass es keine Wunderwaffe geben würde, dass das Schreiben von Software weiterhin schwierig sein würde.
Ich empfehle Ihnen nachdrücklich, sein Buch zu lesen: Insbesondere empfehle ich die Silver Anniversary Edition mit einem zusätzlichen Aufsatz "No Silver Bullet". Dabei überprüft er die vorgeschlagenen Lösungen auf Komplexität und betrachtet deren Auswirkungen. (Was er am effektivsten findet, ist Shrink-Wrap-Software. Schreiben Sie einmal etwas Komplexes und verkaufen Sie Tausende oder Millionen Exemplare.)
Jetzt hilft die objektorientierte Programmierung, wenn sie richtig gemacht wird, indem sie Abstraktionen erzeugt und Komplexität verbirgt. Ein Objekt einer Klasse hat ein bestimmtes definiertes Verhalten, aus dem wir schließen können, ohne sich um die Komplexität der Implementierung zu kümmern. Ordnungsgemäß geschriebene Klassen haben eine geringe Kopplung untereinander und Divide-and-Conquer ist eine hervorragende Möglichkeit, mit Komplexität umzugehen, wenn Sie damit durchkommen können. Sie haben auch eine hohe Kohäsion, da sie eine Reihe von Funktionen und Daten sind, die sehr eng miteinander zusammenhängen.
quelle
Ich gehe davon aus, dass Sie in Kürze einige bessere Antworten erhalten, aber hier ist eine einfache:
OOP hilft * bei der Komplexität, indem es Software so modelliert, wie wir alles andere auf der Welt modellieren. Es ist im Allgemeinen einfacher, sich ein Kugelobjekt vorzustellen, das mit einem Wandobjekt interagiert, als sich eine Reihe von Routinen und Datenstrukturen vorzustellen, um dasselbe zu tun, da es näher daran liegt, wie wir mit der realen Welt interagieren.
* Weil nichts die Komplexität lösen kann
quelle
Ich denke, dass die aktuelle Mainstream-Definition von OOP keine gute Lösung für das Management von Komplexität ist.
Wenn Sie zu seinen Wurzeln zurückkehren, glaube ich, dass Alan Kay in hohem Maße von "lisp" beeinflusst wurde.
Da Lisp durch die Akzeptanz des Mainstreams nicht beschädigt wurde, ist es ihm wahrscheinlich gelungen, seine Kernwerte zu bewahren. Ich denke also, ein Blick auf die Art und Weise, wie Lispel dieses Problem der Komplexität angeht, gibt uns einen Einblick, und wir können auf dieser Grundlage beurteilen, wie nützlich OOP im Umgang mit Komplexität ist.
Wenn Sie sich das Ende der "Lecture 3a: Henderson Escher Example" von SICP ansehen , schlägt Hal Abelson vor, dass die Komplexität nicht durch Aufteilen der Aufgabe in kleinere Teilaufgaben, sondern durch Erstellen von Abstraktionsebenen bewältigt wird. Auf der höchsten Ebene drücken Sie die Lösung für das komplizierte Problem im Sinne der Lösung für die niedrigere Abstraktionsebene aus.
Ich denke, OOP war ursprünglich als Mechanismus gedacht, um diese Abstraktionsebenen zu erzeugen.
Leider wird OOP heutzutage (ab) verwendet, um Spaghetti-Code / Strukturen zu schreiben.
Ich werde ein Beispiel erfinden: ein FPS-Multiplayer-Spiel.
Auf der höchsten Ebene funktioniert das Spiel, indem eine Gruppe von Spielern auf einer Karte herumläuft und mit Waffen aufeinander schießt.
Auf der nächstniedrigeren Ebene müssen wir über Karten, Waffen und Spieler sprechen. Vielleicht können wir über sie als physische Objekte sprechen, die in der Welt des Spiels interagieren.
Auf der nächstniedrigeren Ebene können wir darüber sprechen, wie Objekte physisch interagieren (Bewegung, Kollisionen usw.).
Und so weiter und so fort.
Dies bedeutet (und ich zitiere aus SICP), dass wir auf jeder Ebene nicht nur ein bestimmtes Problem lösen, sondern auch eine Klasse von Problemen, die in die Nachbarschaft des Problems fallen, das wir haben. versuche zu lösen. Wenn sich also die Beschreibung des Problems geringfügig ändert, ist wahrscheinlich nur eine geringfügige Änderung der Lösung erforderlich.
Der kluge Weg, OOP zu verwenden, besteht darin, Abstraktionsebenen zu erstellen. Auf jeder Abstraktionsebene lösen Sie das vorliegende Problem mit den "Objekten" der Ebene, die direkt darunter liegt.
Hier ist das Stück, das ich aus der Vorlesung zitiert habe: http://www.youtube.com/watch?v=CYtrfncMqHQ
quelle
Wie immer bin ich nicht mit allen einverstanden. OOP bietet Ihnen keine Tools zum Verwalten von Komplexität, sondern verursacht eine enorme Komplexität, da es sich um ein unangemessenes und mathematisch falsches Paradigma handelt. Es verwirrt Programmierer ohne Ende, Dinge mit OOP zu modellieren, die mit OOP nicht modelliert werden können.
Meiner Ansicht nach ist die wegweisende Arbeit hier Meyers objektorientierte Software-Konstruktion. Es enthält eine Reihe von Anforderungen, darunter eine, die ich für entscheidend halte: das Open-Closed-Prinzip. Dies besagt, dass ein Objekt zur Erweiterung geöffnet und zur Verwendung gleichzeitig geschlossen sein muss.
Meyer leitet die Objektorientierung aus diesen Anforderungen ab, wie sie in Eiffel enthalten sind. Die Verkapselung sorgt für den Abschluss, die Offenheit der Vererbung, und das "Ding", von dem die Rede ist, ist die Klasse.
Ich betrachte diese Arbeit als gute Wissenschaft, weil Meyer nachweislich falsch lag und es aufgrund der Qualität seiner Arbeit möglich ist, den Fehler genau zu lokalisieren und zu beheben.
Der Fehler macht die Klasse oder den Typ zur Einheit der Modularität. Das ist falsch und nachweislich auch so. Sogar Meyer erkannte das Problem (Kovarianzproblem genannt), dass OOP keine Aritätsrelationen größer als eins verarbeiten kann (dh, OOP funktioniert gut für Eigenschaften, scheitert jedoch an binären Relationen). In Eiffel führte dieses Problem zu einer Unstimmigkeit im Typensystem!
Die Lösung liegt auf der Hand. Die Modularitätseinheit muss größer als ein einzelner Typ sein. Es muss aus mehreren Typen und den dazugehörigen Methoden bestehen.
Es ist nicht verwunderlich, dass dieses Abstraktionsmodell von der mathematischen Abstraktionstheorie, der Kategorietheorie, gestützt wird: Typen sind Objekte einer Kategorie, Methoden (Funktionen) sind Pfeile.
Bei diesem Modell sind die Darstellungen mehrerer Typen einer Reihe von Funktionen bekannt. Die Darstellung ist vor der Öffentlichkeit verborgen, das ist also eine Kapselung, aber wir verwenden Module, keine Klassen.
Die Standard Meta-Language (SML) und Ocaml basieren direkt auf diesem Modell. Ocaml hat auch Klassen und OOP: Es ist nicht nutzlos, weil OOP Ihnen den Versand von Eigenschaften ermöglicht, auch bekannt als dynamische Bindung. Die meisten Probleme der realen Welt betreffen jedoch Beziehungen, und es ist nicht verwunderlich, dass Klassen in Ocaml nicht häufig verwendet werden.
Es ist nicht verwunderlich, dass die Vererbung in der C ++ Standard-Vorlagenbibliothek kaum verwendet wird.
Die einfache Tatsache ist, dass OOP Ihnen nicht die richtigen Werkzeuge zur Verfügung stellt, um mit Komplexität umzugehen. Es bietet Ihnen nicht einmal die Werkzeuge, um wirklich einfache Probleme zu lösen. Stattdessen hat es zwei Generationen von Programmierern irregeführt und verwirrt. OOP ist weit davon entfernt zu helfen, das Böse und Schlechteste, was der Programmierung zugestoßen ist, seit C, Fortran und Cobol müde geworden sind.
quelle
Objektorientierte Programmierung hat Wurzeln, die bis in die 1960er Jahre zurückreichen. Da Hard- und Software immer komplexer wurden, wurde die Verwaltbarkeit häufig zu einem Problem. Die Forscher untersuchten Möglichkeiten zur Aufrechterhaltung der Softwarequalität und entwickelten eine objektorientierte Programmierung, um häufig auftretende Probleme zu lösen, indem sie diskrete, wiederverwendbare Einheiten der Programmierlogik stark betonten .
Ein objektorientiertes Programm kann somit im Gegensatz zu dem herkömmlichen Modell, bei dem ein Programm als Liste von auszuführenden Aufgaben (Subroutinen) angesehen werden, als eine Sammlung von interagierenden Objekten. In OOP kann jedes Objekt Nachrichten empfangen, Daten verarbeiten und Nachrichten an andere Objekte senden. Jedes Objekt kann als eigenständige Maschine mit einer bestimmten Rolle oder Verantwortung angesehen werden. Die Aktionen (oder "Methoden") für diese Objekte sind eng mit dem Objekt selbst verknüpft.
http://en.wikipedia.org/wiki/Object-oriented_programming
Diese Trennung der Belange sowie andere Merkmale der Objektorientierung wie Polymorphismus, Vererbung, Nachrichtenübermittlung, Entkopplung und Kapselung bilden einen logischen und konzeptionellen Rahmen, mit dem die Komplexität großer Programme auf höchst effektive Weise verwaltet werden kann.
quelle
Es gibt viele Arten von Komplexität bei der Softwareentwicklung. Auf der Programmierebene versucht OOP, die Komplexität zu beheben, indem Objekte und Klassen zum Modellieren der Problemdomäne verwendet werden. Ein bekannter Guru sagte, dass Problemlösung nur das Problem repräsentiert, so dass die Lösung die Repräsentation selbst ist. Daher kann durch Abstraktion unter Verwendung von Klassen, Kapselung unter Verwendung von Zugriffsmodifikatoren und -methoden, Vererbung zur Angabe von Beziehungen und Wiederverwendung, Komposition bei der Herstellung von Beziehungen und der Zusammenarbeit zwischen Klassen, Polymorphismus als Mittel zur Vereinfachung der Bestimmung verschiedener Verhaltensweisen in ähnlichen Objekten die Komplexität verwaltet werden.
Es gibt auch andere Möglichkeiten zum Verwalten der Softwarekomplexität, z. B. Logik- (Prolog) und Funktionsprogrammierung (Haskell).
Auf einer höheren Ebene als die Programmierung benötigen wir Entwurfsmuster und -prinzipien, um den OOP zu steuern. Daher verwaltet OOP die Komplexität auf einer niedrigen (Codierungs-) Ebene, während diese Methoden wie Entwurfsmuster und -prinzipien den Entwurf der Lösung auf einer höheren (System- und Anwendungs-) Ebene leiten und die Softwareentwicklung und den Umgang mit Komplexitäten übersichtlicher gestalten.
Um Ihre Frage zu beantworten: Ja, OOP ist nur eine Lösung für den Umgang mit Komplexität unter vielen anderen Lösungen. Es ist eine Lösung auf niedrigem Niveau. Wir brauchen Entwurfsmuster und -prinzipien, um OOP auf einer höheren Ebene zu führen.
quelle
Die objektorientierte Programmierung verwaltet die notwendige und optionale Komplexität, reduziert diese jedoch nicht.
Ich bevorzuge die Definition von Eric Steven Raymond in Die Kunst der Unix-Programmierung , weil sie zwischen essentieller, optionaler und zufälliger Komplexität abgrenzt. http://www.faqs.org/docs/artu/ch13s01.html#id2964646
OOP tut nichts für wesentliche oder optionale Komplexität, sie sind eine Funktion der Anforderungen des Programms. Dies kann sich auf die zufällige Komplexität auswirken, da Sie mit OOP manchmal ein eleganteres Design erstellen können. Manchmal ist das Design jedoch schlechter, wenn OOP verwendet wird.
quelle
Komplexe Probleme können durch Technologie nicht einfacher, sondern nur durch Technologie bewältigt werden.
OOP ist eine Technologie, ein Konzept und ein Weg, um ein Problem anzugehen.
OOP bietet Ihnen die Tools, um ein Design zu erzwingen , mit dem die Komplexität einfacher verwaltet werden kann, aber Sie können genauso gut ein schlechtes Design haben, das Ihre Komplexität erhöht. Mit anderen Worten, wenn Sie nicht richtig eingesetzt werden, können Ihre Probleme technologiebedingte Komplexität aufweisen.
Beachten Sie, dass es viele andere Aspekte gibt, die den Erfolg Ihres Projekts bestimmen (z. B. Projektmanagementstil, Problemdefinition, Änderungsmanagement usw.). Die Technologie , die Sie verwenden , ist nur relevant , in wie viel wird es Ihnen helfen, verwalten das Problem.
Objektorientierte Programmierung kann letztendlich keine Lösung für Komplexität sein. Es ist nur ein Werkzeug, um es zu verwalten. (bei sachgemäßer Verwendung)
quelle
Objektorientierung (wie herkömmlich verwendet) ist unter vielen Umständen ein nützliches Werkzeug, aber es ist keine ausreichende Lösung für Komplexität.
Insbesondere fügt es oft viel " zufällige Komplexität " hinzu. Beispiele sind die Komplexität bei der Vererbung von Implementierungen, die Notwendigkeit, viele "Standardfunktionen" wie equals () und hashCode () usw. bereitzustellen. Eine nette Präsentation von Stuart Halloway zu diesem Thema: " Einfachheit ist nicht einfach "
Objekte in den meisten Sprachen kapseln häufig auch viele veränderliche Zustände ein - was in einer gleichzeitigen Welt zunehmend nach einer schlechten Entwurfsentscheidung aussieht. Ein weiteres interessantes Video von Rich Hickey befasst sich mit der Unterscheidung zwischen Objektidentität und Zustand und wie es ein Fehler sein könnte, die beiden zu verbinden.
quelle
Objektorientierte Programmierung ist ein Weg, ein Problem darzustellen, nicht mehr und nicht weniger. Es ist an und für sich nicht weniger komplex als jedes andere Programmierparadigma. Ein gut gestaltetes OOP-System verwaltet und reduziert die Komplexität, aber es ist auch sehr einfach, ein System zu entwerfen, das viel komplexer als nötig ist und alles behindert.
Wie von C ++ oft gesagt, gibt OOP Ihnen genug Seil, um sich zu erhängen.
quelle
Ich denke JA , nur weil es Ihnen ermöglicht, Komplexität in kleine, in sich geschlossene "Bausteine" zu zerlegen, die Details verbergen, und diese dann zu verwenden, um die Funktionen zu erstellen, die Sie benötigen, Schritt für Schritt, Schicht für Schicht.
Teilen und erobern.
quelle
OOP ist ein Lösungsversuch.
Komplexität lässt sich am besten verwalten, indem Sie Abstraktionen erstellen. Wenn ich meine Daten in nützliche Sammlungen mit erkennbaren Funktionen für diese Sammlungen verwandeln kann, kann ich anfangen, die Sammlungen als diskrete "Dinge" zu betrachten. Das ist die Basis für Klassen und Methoden. In dieser Hinsicht kann ein richtig entworfenes OOP helfen, die Komplexität zu managen.
Irgendwann entschied jemand, dass wir OOP verwenden könnten, um das Problem der Wiederverwendung von Code zu lösen. Ich meine, warum das Rad neu erfinden? Wenn jemand anderes einen Großteil der Arbeit zur Lösung dieses Problems geleistet hat, nutzen Sie das, was er getan hat, und fügen Sie die Optimierungen hinzu, die für Ihr bestimmtes Projekt erforderlich sind. Sie haben eine leistungsstarke, ausgereifte Anwendung mit relativ wenig Arbeit erstellt. OO-Programmierer können sehr produktive Programmierer sein.
Das Endergebnis ist, dass moderne OO-Programmierer am Ende "Zauberlehrlinge" sind, in denen sie eine Reihe großer, unhandlicher Bibliotheken mit ein paar Zeilen "Kleber" zusammenbinden und etwas bekommen, das funktioniert. Sorta. Irgendwie. Meistens. Gibt es mögliche Nebenwirkungen bei der Verwendung dieser Bibliothek mit dieser? Vielleicht. Aber wer hat Zeit, sich wirklich mit dem Code in diesen Bibliotheken auseinanderzusetzen? Vor allem, wenn sich die Bibliotheken weiterentwickeln. Das Ergebnis ist, dass wir am Ende überfüllte Anwendungen haben, in denen ein Programmierer eine Handvoll Klassen und Methoden aus dieser Bibliothek benötigte, aber die App das Gewicht all der ANDEREN Dinge tragen muss, die sie nicht brauchten.
Das Endergebnis ist, dass Sie am Ende viel komplexer sind, als Sie brauchen.
Ein weiterer Mechanismus für den Umgang mit Komplexität, bei dem Sie die Funktionalität trennen möchten. Sie möchten alle Ihre Datenzugriffsfunktionen an einem Ort haben. Sie möchten alle Funktionen Ihrer Benutzeroberfläche an einem Ort haben. Sie möchten alle Ihre Controller an einem Ort haben. Sie erstellen also verschiedene Klassen, die verschiedene Teile der Funktionalität verwalten. So weit, ist es gut. Und das skaliert bis zu einem gewissen Grad; Ihre Entwickler, die mit Datenzugriff vertraut sind, können diese Klassen schreiben, Ihre Benutzeroberflächen-Mitarbeiter können die Benutzeroberflächen-Klassen schreiben usw. Alles ist in Ordnung und gut.
Bis Sie etwas pflegen müssen, das von jemand anderem geschrieben wurde.
Ja, es ist gut zu wissen, dass sich alle Datenzugriffsfunktionen hier befinden. Aber wie heißen sie?
Diese Methode ruft diese Methode für diese Klasse auf. Aber wenn ich mir die Klassendefinition anschaue, gibt es keine Methode mit diesem Namen. Oh, das wird von etwas anderem geerbt, einer oder zwei Schichten in der Vererbungskette. Warte eine Minute; diese Klasse eine Schnittstelle implementiert? Wie viele verschiedene Klassen implementieren diese Schnittstelle? Und wir verwenden ein kompliziertes Laufzeitsystem (ich sehe Sie, Spring), um Instanzen von Klassen zur Laufzeit zu "verbinden"? Wo kann JEDE Klasse verwendet werden, die diese Schnittstelle implementiert?
Sie haben am Ende viele kleine, diskrete Methoden, die präzise Dinge tun. Aber das nennt man das, in einer anderen Klasse. Welches nennt das eine, in noch einer anderen Klasse. Welches nennt das eine, in noch einer anderen Klasse. Das nennt man in einer zusätzlichen Klasse. Was ein Ergebnis eines bestimmten Typs zurückgibt. Auf die Sie eine Methode aufrufen müssen, um eine bestimmte Sache zu tun. Was ein Ergebnis eines anderen Typs zurückgibt. Etc.
Dafür gibt es einen Begriff: Spaghetti-Code.
Am Ende steht ein sehr komplexes System zur Verfügung, das nur zum Erstellen des Codes benötigt wird. Daher IDEs wie Visual Studio, Eclipse und NetBeans. Alle haben eine signifikante Lernkurve. In der Tat sind viele von ihnen in der Lage, mehrere Tools zu kapseln / zusammenzufassen, die von verschiedenen Gruppen entwickelt wurden, von denen jede ihre eigenen Lernkurven hat.
Ist das der Umgang mit Komplexität?
Das Debuggen von Code ist doppelt so schwierig wie das Schreiben. Viel Glück beim Debuggen einiger dieser Sachen. Insbesondere, wenn mehrere Bibliotheken verwendet werden, die zur Laufzeit mithilfe eines Abhängigkeitsinjektionssystems "miteinander verbunden" sind.
Zusammenfassend lässt sich sagen, dass OOP ein vielversprechendes Tool zur Verwaltung der Komplexität darstellt. Die Realität ist, dass der resultierende Code furchtbar aufgebläht ist (weil Sie nicht nur die benötigten Teile aus all diesen verknüpften Bibliotheken extrahieren können), und Sie benötigen ausgeklügelte Tools, um nur durch den Code zu navigieren. Es wird schnell zu einem Alptraum für die Instandhaltung.
IMHO, es ist ein Nettoverlust; es fügt mehr Komplexität hinzu als es beseitigt. Sie ermöglicht es Ihnen, Dinge zu tun, die ohne sie außerordentlich schwierig, möglicherweise sogar unmöglich wären. Aber jedes große Projekt entwickelt sich schnell zu einem unhaltbaren Durcheinander.
Wenn Sie bereits wissen, wie es funktioniert, und Sie sich daran erinnern können, haben Sie möglicherweise eine Chance, es beizubehalten.
Denken Sie daran, das Eagleson-Gesetz anzuwenden: Jeder eigene Code, den Sie seit sechs Monaten nicht mehr gelesen haben, kann auch von jemand anderem geschrieben werden.
quelle
Zu einem gewissen Grad...
Warum? Weil es eine sehr logische Modularität ermöglicht. Zumindest im Vergleich zur prozeduralen Programmierung, bei der es zu verlockend ist, nur riesige Stapel Spaghetti-Code zu schreiben.
quelle
Der Grund, warum die objektorientierte Programmierung uns dabei zu helfen scheint, mit Komplexität umzugehen, liegt darin, dass wir gezwungen sind, Code auf eine bestimmte Art und Weise zu schreiben, anstatt auf eine Vielzahl von Arten. Die aufgabenorientierte Programmierung ist viel intuitiver, weshalb die Programmierung so begann. Die Objektorientierung erfordert Training und Übung, um sie effektiv zu verstehen und anzuwenden. Indem Sie jedoch die Programmierung auf einen bestimmten Pfad beschränken, können die geschulten Personen den geschriebenen Code effektiv verwalten.
Es ist nicht logischer oder realer als jede andere Methode. Es ist nur eine Möglichkeit, die Problemlösung durch ähnliche Objektive zu fokussieren. Viele technische Fachleute verwenden das Paradigma einer nicht intuitiven starren Methodik, um die Komplexität ihrer Aufgaben zu bewältigen.
Eine dritte Methode, um mit Komplexität umzugehen, wäre die funktionale Programmierung, und es wird wahrscheinlich auch in Zukunft andere neue Methoden geben.
quelle
Ich denke, es ist eher eine Lösung für die Wartbarkeit, denn als Programmierer sollten Sie Methoden dort platzieren, wo Sie die Daten haben, und so ein Objektmodell Ihrer Anwendung erstellen.
Ja, es ist auch eine Lösung für die Komplexität, indem ein Modell bereitgestellt wird, mit dem Sie Ihren Code auf natürliche Weise als Objekte mit Eigenschaften und möglichen Aktionen "sehen" können
quelle