it-swarm.com.de

Benötigen wir wirklich OO Sprachen), um die Komplexität der Software zu verwalten?

Dies wird eine sehr untechnische, weiche Frage sein, und ich bin mir nicht sicher, ob dies die richtige Plattform ist. Aber ich bin ein CS-Anfänger, also hoffe ich, dass ihr es toleriert.

Im ersten Semester wurden wir mit OOP Konzepten wie Kapselung, Ausblenden von Daten, Modularität, Vererbung usw. durch Java und UML. (Java ist meine erste) vertraut gemacht Programmiersprache)

So wie ich es verstehe, ist OOP ein Weg, um die Komplexität von Software zu verwalten. Aber seine Prinzipien sind nicht neu oder einzigartig, sie sind in gewissem Sinne universell für alle technischen Bereiche.

Zum Beispiel ist ein Auto eine sehr komplexe Struktur, deren Komplexität durch eine Hierarchie modularer und gekapselter Komponenten mit genau definierten Verhaltensweisen und Schnittstellen verwaltet wird.

Aber ich verstehe den Grund für die Einführung eines neuen Programmierparadigmas nicht. Ich denke, dass alle Prinzipien, die zur Verwaltung der Komplexität verwendet werden, durch prozedurale Programmiersprachen realisiert werden können. Aus Gründen der Modularität können wir das Programm beispielsweise einfach in viele kleine Programme unterteilen, die genau definierte Aufgaben ausführen, deren Code in separaten Dateien enthalten ist. Diese Programme würden durch ihre genau definierten Ein- und Ausgaben miteinander interagieren. Die Dateien können geschützt (verschlüsselt?) Sein, um eine Kapselung zu erreichen. Zur Wiederverwendung von Code können wir diese Dateien einfach aufrufen, wann immer sie in neuen Programmen benötigt werden. Erfasst dies nicht alles, was OOP ist oder fehlt mir etwas sehr Offensichtliches?

Ich bitte nicht um einen Beweis dafür, dass OOP Komplexität verwaltet. Meiner Meinung nach ist dies sicherlich der Fall. Aber ich denke, dass alle Prinzipien, die zur Verwaltung von Komplexität verwendet werden, wie Modularität, Kapselung, Verstecken von Daten usw., möglich sind sehr einfach durch prozedurale Sprachen zu implementieren. Warum also wirklich OOP, wenn wir die Komplexität ohne sie verwalten können?

212
steakexchange

Lassen Sie mich mit einer wirklich niedrigen theoretischen Antwort versuchen :)

Was Sie wirklich fragen, ist: Warum Unterstützung für Objektorientierung (OO) direkt in die Sprache aufnehmen, wenn prozedurale Sprachen zum Entwerfen und Schreiben von OO Code? verwendet werden können

Und die Antwort lautet: m einen Standard dafür zu haben, wie OO wird im Quellcode ausgedrückt, damit Sie nicht 22 verschiedene Implementierungen für dieselbe Abstraktion erhalten.

Nehmen wir zum Beispiel an, ich erstelle ein MagicButton und ein MagicSlider, die in einem Benutzeroberflächensystem verwendet werden können. Ich brauche eine Möglichkeit, die Methoden zu gruppieren, die mit dem MagicButton verwendet werden können, die Methoden, die nur mit dem MagicSlider verwendet werden können, und die Methoden, die von beiden verwendet werden können. Diese Objekte haben einige Methoden gemeinsam, da sie beide Magic-GUI-Objekte sind.

Ich kann die Gruppierung durchführen, indem ich Funktionen auf besondere Weise benenne MagicSlider_DoSomething ..., indem die Methoden in bestimmte Dateien aufgenommen werden, die auf besondere Weise benannt wurden MagicSliderMethods.XXX, oder ich könnte einen anderen speziellen Weg finden, um dasselbe zu tun. Wenn es in der Sprache keine Standardmethode gibt, werde ich es anders machen als Sie und anders als alle anderen. Dies erschwert das Teilen von Code erheblich.

Ja, verspäteter Versand - virtuelle Methoden in OO Sprachen) können in prozeduralen Sprachen implementiert werden, aber es gibt so viele verschiedene Möglichkeiten, sie zu implementieren. Je nachdem, wer den Code geschrieben hat, werden Sie unterschiedliche Methoden erhalten Implementierungen von OO innerhalb desselben Programms.

Denken Sie an den schlechten Wartungsentwickler. Diese Person muss unterschiedliche Objektabstraktionen und unterschiedliche Methoden zum Aufrufen virtueller Methoden verwalten, je nachdem, wer den ursprünglichen Code geschrieben hat.

Außerdem: Wenn die Abstraktionen in der Sprache vorhanden sind, können erweiterte Code-Editoren wie Eclipse viele statische Analysen des Codes durchführen. Zum Beispiel kann Eclipse eine Liste aller Methoden anbieten, die für ein Objekt verwendet werden können, sowie die automatische Implementierung leerer "TODO-Methoden". Eclispe weiß genau, welche Methoden Ihre Klasse implementieren muss, basierend darauf, welche Klassen Sie erweitern und welche Schnittstellen Sie implementieren. Dies wäre fast unmöglich, wenn es keinen Sprachstandard für OO gäbe.

176
MTilsted

Im ersten Semester wurden wir mit OOP Konzepten wie Kapselung, Ausblenden von Daten, Modularität, Vererbung usw. durch Java und UML. (Java ist meine erste) vertraut gemacht Programmiersprache)

Keines davon ist OOP Konzepte. Sie existieren alle außerhalb von OO, unabhängig von OO und viele wurden sogar vor OO erfunden.

Wenn Sie also denken, dass das das ist, worum es bei OO geht), dann ist Ihre Schlussfolgerung richtig: Sie können all dies in prozeduralen Sprachen tun, weil sie nichts mit OO zu tun haben .

Zum Beispiel ist eine der wegweisenden Arbeiten zur Modularität Über die Kriterien, die beim Zerlegen von Systemen in Module verwendet werden sollen . Es gibt keine Erwähnung von OO dort drin.) (Es wurde 1972 geschrieben, bis dahin OO war immer noch eine dunkle Nische, obwohl es bereits mehr als ein Jahrzehnt war alt.)

Während Datenabstraktion in OO wichtig ist, ist es eher eine Konsequenz des Hauptmerkmals von OO (Messaging) als Es ist ein definierendes Merkmal. Außerdem ist es sehr wichtig, sich daran zu erinnern, dass es verschiedene Arten Datenabstraktion gibt. Die beiden heute am häufigsten verwendeten Arten der Datenabstraktion (wenn wir "überhaupt keine Abstraktion" ignorieren, die wahrscheinlich immer noch häufiger als die beiden anderen zusammen verwendet wird) sind Abstrakte Datentypen und Objekte. Wenn Sie also "Information Hiding", "Encapsulation" und "Data Abstraction" sagen, haben Sie nichts über OO gesagt, da OO ist nur eins Form der Datenabstraktion, und die beiden sind in der Tat grundlegend unterschiedlich:

  • Bei abstrakten Datentypen ist der Abstraktionsmechanismus das Typsystem; Es ist das Typsystem, das die Implementierung verbirgt. (Das Typsystem muss nicht unbedingt statisch sein.) Bei Objekten ist die Implementierung hinter einer prozeduralen Schnittstelle verborgen, für die keine Typen erforderlich sind. (Zum Beispiel kann es mit Schließungen implementiert werden, wie es in ECMAScript gemacht wird.)
  • Bei abstrakten Datentypen werden Instanzen verschiedener ADTs voneinander gekapselt, aber Instanzen des ADT same können die Darstellung und die private Implementierung des jeweils anderen überprüfen und darauf zugreifen. Objekte sind immer eingekapselt von alles. Nur das Objekt selbst kann seine eigene Darstellung überprüfen und auf seine eigene private Implementierung zugreifen. Kein anderes Objekt, nicht einmal andere Objekte desselben Typs, andere Instanzen derselben Klasse, andere Objekte mit demselben Prototyp, Klone des Objekts oder was auch immer das kann. Keine.

Dies bedeutet übrigens, dass Klassen in Java nicht objektorientiert sind. Zwei Instanzen derselben Klasse can Greifen auf die gegenseitige Darstellung und private Implementierung zu. Daher sind Instanzen von Klassen keine Objekte, sondern ADT-Instanzen. Java interfaces bietet jedoch do eine objektorientierte Datenabstraktion. Mit anderen Worten: Nur Instanzen von Schnittstellen sind Objekte in Java, Instanzen von Klassen nicht.

Grundsätzlich können Sie für Typen nur Schnittstellen verwenden. Dies bedeutet Parametertypen von Methoden und Konstruktoren, Rückgabetypen von Methoden, Typen von Instanzfeldern, statischen Feldern und lokalen Feldern, das Argument für einen instanceof -Operator oder einen Cast-Operator und Typargumente für einen generischen Typkonstruktor muss immer Schnittstellen sein. Eine Klasse darf nirgendwo anders direkt nach dem Operator new verwendet werden.

Aus Gründen der Modularität können wir das Programm beispielsweise einfach in viele kleine Programme unterteilen, die genau definierte Aufgaben ausführen, deren Code in separaten Dateien enthalten ist. Diese Programme würden durch ihre genau definierten Ein- und Ausgaben miteinander interagieren. Die Dateien können geschützt (verschlüsselt?) Sein, um eine Kapselung zu erreichen. Zur Wiederverwendung von Code können wir diese Dateien einfach aufrufen, wann immer sie in neuen Programmen benötigt werden. Erfasst dies nicht alles, was OOP ist oder fehlt mir etwas sehr Offensichtliches?

Was Sie beschreiben ist OO.

Das ist in der Tat eine gute Möglichkeit, über OO nachzudenken. Genau das hatten die ursprünglichen Erfinder von OO im Sinn). (Alan Kay ging noch einen Schritt weiter: Er stellte sich viele kleine Computer vor, die sich über das Netzwerk gegenseitig Nachrichten senden.) Was Sie "Programm" nennen, wird normalerweise als "Objekt" bezeichnet und anstelle von "Aufruf" sagen wir normalerweise "Nachricht senden".

Bei der Objektorientierung dreht sich alles um Messaging (aka dynamischer Versand). Der Begriff "objektorientiert" wurde von Dr. Alan Kay, dem Hauptdesigner von Smalltalk, geprägt, und er definiert es so :

OOP bedeutet für mich nur Messaging, lokale Aufbewahrung und Schutz sowie das Verstecken von Staatsprozessen und die extreme Spätbindung aller Dinge.

Lassen Sie uns das aufschlüsseln:

  • messaging ("Versand virtueller Methoden", wenn Sie mit Smalltalk nicht vertraut sind)
  • staatsprozess sollte sein
    • lokal beibehalten
    • geschützt
    • versteckt
  • extreme Spätbindung aller Dinge

In Bezug auf die Implementierung ist Messaging ein spät gebundener Prozeduraufruf. Wenn Prozeduraufrufe spät gebunden sind, können Sie zum Entwurfszeitpunkt nicht wissen, was Sie werden aufrufen, sodass Sie keinen Anruf tätigen können Annahmen über die konkrete Darstellung des Staates. Es geht also wirklich um Messaging. Spätes Binden ist eine Implementierung von Messaging, und die Kapselung ist eine Folge davon.

Später stellte er klar, dass " Die große Idee ist 'Messaging' ", und bedauert, dass er es "objektorientiert" statt "nachrichtenorientiert" genannt hat, weil der Begriff "objektorientiert" das setzt Konzentrieren Sie sich auf das Unwichtige (Objekte) und lenken Sie von dem ab, was wirklich wichtig ist (Messaging):

Nur eine sanfte Erinnerung daran, dass ich mir bei der letzten OOPSLA einige Mühe gegeben habe, um alle daran zu erinnern, dass Smalltalk nicht nur NICHT seine Syntax oder die Klassenbibliothek ist, es geht nicht einmal um Klassen. Es tut mir leid, dass ich vor langer Zeit den Begriff "Objekte" für dieses Thema geprägt habe, weil es viele Leute dazu bringt, sich auf die geringere Idee zu konzentrieren.

Die große Idee ist "Messaging" - darum geht es beim Kern von Smalltalk/Squeak (und es ist etwas, das in unserer Xerox PARC-Phase nie ganz abgeschlossen wurde). Die Japaner haben ein kleines Wort - ma - für "das, was dazwischen liegt" - vielleicht ist das nächste englische Äquivalent "interstitial". Der Schlüssel zur Herstellung großartiger und erweiterbarer Systeme liegt viel mehr darin, die Kommunikation der Module zu bestimmen, als ihre internen Eigenschaften und Verhaltensweisen. Denken Sie an das Internet - um zu leben, muss es (a) viele verschiedene Arten von Ideen und Realisierungen zulassen, die über einen einzelnen Standard hinausgehen, und (b) unterschiedliche Grade sicherer Interoperabilität zwischen diesen Ideen ermöglichen.

(Natürlich konzentrieren sich die meisten Menschen heute nicht einmal auf Objekte, sondern auf Klassen, was noch falscher ist.)

Messaging ist für OO grundlegend, sowohl als Metapher als auch als Mechanismus.

Wenn Sie jemandem eine Nachricht senden, wissen Sie nicht, was er damit macht. Das nur, was Sie beobachten können, ist ihre Antwort. Sie wissen nicht, ob sie die Nachricht selbst verarbeitet haben (d. H. Wenn das Objekt über eine Methode verfügt), ob sie die Nachricht an eine andere Person weitergeleitet haben (Delegierung/Proxy), ob sie sie überhaupt verstanden haben. Darum geht es bei der Kapselung, darum geht es bei OO). Sie können einen Proxy nicht einmal von der Realität unterscheiden, solange er so reagiert, wie Sie es erwarten.

Ein "modernerer" Begriff für "Messaging" ist "dynamischer Methodenversand" oder "virtueller Methodenaufruf", aber das verliert die Metapher und konzentriert sich auf den Mechanismus.

Es gibt also zwei Möglichkeiten, die Definition von Alan Kay zu betrachten: Wenn Sie sie für sich allein betrachten, können Sie feststellen, dass Messaging im Grunde genommen ein spät gebundener Prozeduraufruf ist und eine späte Bindung eine Kapselung impliziert, sodass wir daraus schließen können, dass # 1 und # 2 sind tatsächlich redundant und OO dreht sich alles um spätes Binden.

Später stellte er jedoch klar, dass das Wichtigste das Versenden von Nachrichten ist, sodass wir es aus einem anderen Blickwinkel betrachten können: Das Versenden von Nachrichten ist spät. Wenn Messaging das nur Ding wäre, wäre # 3 trivial wahr: Wenn es nur eines gibt und dieses Ding spät gebunden ist, dann alles Dinge sind spät gebunden. Und wieder folgt die Kapselung aus dem Messaging.

Ähnliche Punkte werden auch in Zum Verständnis der Datenabstraktion, überarbeitet von William R. Cook und auch in seinem Vorschlag für vereinfachte, moderne Definitionen von "Objekt" und "Objektorientiert" :

Der dynamische Versand von Operationen ist das wesentliche Merkmal von Objekten. Dies bedeutet, dass die aufzurufende Operation eine dynamische Eigenschaft des Objekts selbst ist. Operationen können nicht statisch identifiziert werden, und es gibt im Allgemeinen keine Möglichkeit, genau zu wissen, welche Operation als Antwort auf eine bestimmte Anforderung ausgeführt wird, außer durch Ausführen. Dies ist genau das gleiche wie bei erstklassigen Funktionen, die immer dynamisch versendet werden.

In Smalltalk-72 gab es nicht einmal Objekte! Es gab nur Nachrichtenströme, die analysiert, umgeschrieben und umgeleitet wurden. Zuerst kamen Methoden (Standardmethoden zum Parsen und Umleiten der Nachrichtenströme), später Objekte (Gruppierungen von Methoden, die einen privaten Status haben). Die Vererbung erfolgte viel später, und Klassen wurden nur eingeführt, um die Vererbung zu unterstützen. Hätte Kays Forschungsgruppe bereits über Prototypen gewusst, hätten sie wahrscheinlich nie Klassen eingeführt.

Benjamin Pierce in Typen und Programmiersprachen argumentiert, dass das definierende Merkmal der Objektorientierung Open Recursion ist.

Also: Laut Alan Kay dreht sich bei OO alles um Messaging. Laut William Cook dreht sich bei OO alles um den Versand dynamischer Methoden (was wirklich dasselbe ist) Laut Benjamin Pierce dreht sich bei OO alles um Open Recursion, was im Grunde bedeutet, dass Selbstreferenzen dynamisch aufgelöst werden (oder zumindest ist dies eine Art, darüber nachzudenken), oder mit anderen Worten , Nachrichten.

Wie Sie sehen können, hat die Person, die den Begriff "OO" geprägt hat, eine eher metaphysische Sicht auf Objekte, Cook eine eher pragmatische Sicht und Pierce eine sehr strenge mathematische Sicht. Aber das Wichtigste ist: Der Philosoph, der Pragmatiker und der Theoretiker sind sich einig! Messaging ist die einzige Säule von OO. Zeitraum.

Beachten Sie, dass hier keine Vererbung erwähnt wird! Vererbung ist für OO nicht wesentlich. Im Allgemeinen haben die meisten OO - Sprachen eine Möglichkeit zur Wiederverwendung der Implementierung, dies muss jedoch nicht unbedingt eine Vererbung sein. Dies kann beispielsweise auch eine Form der Delegierung sein. Der Vertrag von Orlando diskutiert Delegation als Alternative zur Vererbung und wie unterschiedliche Formen der Delegation und Vererbung zu unterschiedlichen Gestaltungspunkten innerhalb der Gestaltungsraum objektorientierter Sprachen. (Beachten Sie, dass selbst in Sprachen, die die Vererbung unterstützen, wie Java, tatsächlich gelernt wird, dies zu vermeiden, was wiederum darauf hinweist, dass dies für OO nicht erforderlich ist.)

211
Jörg W Mittag

Ich denke jedoch, dass alle Prinzipien, die zur Verwaltung der Komplexität verwendet werden, wie Modularität, Kapselung, Ausblenden von Daten usw., sehr einfach durch prozedurale Sprachen implementiert werden können.

Wenn Sie "sehr leicht" sagen, geben Sie eine sehr kühne Erklärung ab. Ich lese es so: "Ich sehe die Schwierigkeit nicht, deshalb darf sie nicht sehr groß sein." Wenn man es so formuliert, wird klar, dass man nicht fragt, warum wir OO brauchen, sondern warum nicht die Schwierigkeiten, auf die andere Programmierparadigmen gestoßen sind, die zur Erfindung von OO sofort für mich ersichtlich? "

Eine Antwort auf diese Frage ist, dass viele dieser Schwierigkeiten bei den Programmen, an denen Sie arbeiten, nicht vorhanden sind. Sie werden nicht aufgefordert, den 40 Jahre alten Spaghetti-Code zu aktualisieren. Sie versuchen nicht, einen neuen Anzeigemanager für ein Betriebssystem zu schreiben. Sie debuggen keine verteilten Multithread-Anwendungen.

Für viele Arten von Spielzeugprogrammen, mit denen wir CS-Studenten beauftragt sind, könnten wir sie genauso gut in BASIC oder Assembly schreiben wie Java oder Python. Das liegt an der inhärenten Komplexität des Die Aufgaben sind so gering, es gibt nur einen Entwickler, es gibt keine Probleme mit der Interoperabilität, die Leistung spielt keine Rolle, und der Code wird wahrscheinlich nur ein paar Mal auf einem Computer ausgeführt.

Stellen Sie sich vor, Sie nehmen einen Studentenfahrer und bitten ihn, in der Hauptverkehrszeit mit einem Schaltgetriebe ohne Synchronisation auf eine belebte Straße zu fahren und einen steilen Hügel hinaufzufahren. Katastrophe. Warum? Sie sind nicht in der Lage, die Komplexität zu verwalten, die erforderlich ist, um alle für die Aufgabe erforderlichen Regeln gleichzeitig zu befolgen.

Stellen Sie sich nun denselben Studenten und dasselbe Fahrzeug vor, die auf einem leeren Parkplatz im Schritttempo fahren. Sie sind in Ordnung, weil ihr Können der Aufgabe angemessen ist. Es gibt keinen Druck, wenig Risiko, und sie können die einzelnen Teilaufgaben des Startens, Kuppelns, Schaltens, Beschleunigens und Lenkens nacheinander übernehmen.

Dieser Student könnte fragen, warum wir Automatikgetriebe haben, wenn ein erfahrener Fahrer all diese Dinge gleichzeitig tun kann? Die Antwort ist, dass ein ausreichend erfahrener Fahrer unter optimalen Bedingungen keine Automatik benötigt. Aber wir sind nicht alle Berufskraftfahrer in Topform, und wir möchten in der Regel die Bequemlichkeit, dass die Konstrukteure des Autos sich um all diese Komplexität kümmern.

Ein erfahrener, disziplinierter Programmierer kann in der Tat ein funktionierendes hochkomplexes System in C oder Assembly erstellen. Aber wir sind nicht alle Linus Torvalds. Wir sollten es auch nicht sein müssen, um nützliche Software zu erstellen.

Ich persönlich habe kein Interesse daran, alle Merkmale einer modernen Sprache neu erfinden zu müssen, bevor ich das vorliegende Problem überhaupt ansprechen kann. Wenn ich eine Sprache nutzen kann, die Lösungen für bereits gelöste Probleme enthält, warum sollte ich das nicht tun?

Ich werde Ihre Frage also umdrehen und Sie fragen, warum wir sie nicht verwenden sollten, wenn Sprachen praktische Funktionen wie Kapselung und Polymorphismus bieten.

66
Clement Cherlin

Was Sie beschreiben, ist nicht OOP, sondern Abstraktion. Abstraktion ist in allen modernen Designmodellen vorhanden, auch in solchen, die nicht OOP sind. Und OOP ist eine sehr spezifische Art der Abstraktion.

Erstens ist es erwähnenswert, dass es keine einheitliche Definition von OOP gibt, so dass es möglicherweise Menschen gibt, die mit dem, was ich als OOP charakterisiere, nicht einverstanden sind.

Zweitens ist es wichtig, sich daran zu erinnern, dass OOP) von traditionellen Designmodellen inspiriert wurde, sodass die Ähnlichkeiten mit dem Autodesign kein Zufall sind.

Hier sind jedoch einige Möglichkeiten: OOP ist nuancierter als das, was Sie gesagt haben:

  • Kapselung: Hier geht es nicht nur darum, eine festgelegte Schnittstelle für ein Modul zu haben (d. H. Abstraktion), sondern darum, den Zugriff über diese Schnittstelle hinaus zu verbieten. In Java ist der Zugriff auf eine private Variable ein Kompilierungsfehler, während Sie in Ihrem Fahrzeugdesign (in einigen Fällen) Dinge auf eine Weise verwenden können, die sich von der beabsichtigten Schnittstelle unterscheidet.

  • Vererbung: Dies ist wirklich das, was OOP einzigartig macht. Sobald Sie eine Schnittstelle definiert haben, können Sie diese erstellen Mehrere Dinge implementieren diese Schnittstelle, und Sie können dies auf heirarchische Weise tun, indem Sie bestimmte Teile ihrer Implementierung ändern, während erben alle vorherigen Teile, wodurch die Codeduplizierung massiv reduziert wird.

    Wenn Sie in Bezug auf die gekapselten Komponenten eines Autos denken, gibt es nicht wirklich ein Äquivalent dazu. Es gibt für mich keine Möglichkeit, ein Zahnrad herzustellen, indem ich ein anderes Zahnrad nehme und einen bestimmten Teil seiner Implementierung ändere. (Zumindest glaube ich nicht, ich weiß nicht viel über Autos).

  • Polymorphismus : Sobald Sie eine Schnittstelle definiert haben, sollte alles, was diese Schnittstelle verwendet, unter dem Gesichtspunkt der verfügbaren Operationen nicht unterscheidbar sein, und Sie sollten dies nicht tun Sie müssen nicht wissen, welche Implementierung zur Verwendung einer Schnittstelle verwendet wird. Hier werden Subtypisierung und das Liskov-Substitutionsprinzip wichtig.

  • Kopplung : Ein Schlüsselaspekt von OOP ist, dass wir Dinge eng mit denselben Operationen verknüpfen und die verschiedenen verteilen Formulare, die sie haben können. Daten werden mit Operationen für diese Daten gebündelt. Dies bedeutet, dass es sehr einfach ist, eine neue Form von Daten hinzuzufügen (eine neue Implementierung), aber sehr schwierig, einer Schnittstelle eine neue Operation hinzuzufügen (da Sie ' Dies muss im Gegensatz zu algebraischen Datentypen in funktionalen Sprachen stehen, bei denen es sehr einfach ist, eine neue Operation hinzuzufügen (Sie schreiben nur eine Funktion, die alle Fälle behandelt), dies ist jedoch schwierig Fügen Sie eine neue Variante hinzu (da Sie allen Funktionen einen neuen Fall hinzufügen müssen).

22
jmite

Benötigen wir wirklich OO Sprachen), um die Komplexität der Software zu verwalten?

Dies hängt von der Bedeutung des Wortes "Bedürfnis" ab.

Wenn "brauchen" bedeutet, nein, wir brauchen es nicht.

Wenn "Bedürfnis" bedeutet "bietet starke Vorteile", dann würde ich sagen "Ja", wir wünschen es.

Großes Bild

OO-Sprachen binden Funktionen an Daten.

Sie können diese Bindungs- und Schreibfunktionen vermeiden, die Datenwerte weitergeben.

Aber dann werden Sie wahrscheinlich Konstellationen von Daten haben, die zusammenpassen, und Sie werden anfangen, Tupel, Datensätze oder Wörterbücher von Daten herumzugeben.

Und das ist wirklich alles, was Methodenaufrufe sind: Teilfunktionen für gebundene Datensätze.

Feature für Feature

Merkmale von OOP:

  • Vererbung ermöglicht die Wiederverwendung von Code (Mixins) und Konzept (Abstract Base Classes/Interfaces) - Sie können dies jedoch erreichen, indem Sie Funktionen und Variablen in einem Sub- neu dekorieren Umfang.
  • Die Kapselung ermöglicht das Ausblenden von Informationen, damit wir auf höheren Abstraktionsebenen arbeiten können. Sie können dies jedoch mit Header-Dateien, Funktionen und Modulen tun.
  • Polymorphismus ermöglicht es uns, Argumente unterschiedlichen Typs zu verwenden, solange diese Argumente dieselben Schnittstellen unterstützen - aber wir können dies auch mit Funktionen tun.

Keines dieser Dinge geschieht jedoch so einfach wie bei einer objektorientierten Sprache mit erstklassiger Unterstützung dieser Funktionen.

Verweise

Es gibt viele Kritiker von OOP .

Studien scheinen jedoch darauf hinzudeuten, dass wir durch die Wiederverwendung von Code durch OOP eine höhere Produktivität der Programmierer erzielen. Dies ist ein kontroverser Befund, und einige Forscher sagen, dass sie diese Produktivitätsgewinne unter bestimmten Einschränkungen nicht reproduzieren können. (Quelle)

Fazit

Wir "brauchen" kein OOP. Aber in einigen Fällen will der Benutzer - OOP.

Mein Verständnis ist, dass reife Programmierer im objektorientierten Stil sehr produktiv sein können. Und wenn Pakete Kernobjekte mit einfachen Schnittstellen haben, die leicht zu verstehen sind, können selbst neue Programmierer schnell sehr produktiv werden.

11
Aaron Hall

Ich werde versuchen, mich kurz zu fassen.

Das Kernprinzip von OO ist die Kombination von Daten und Verhalten in einer einzelnen Organisationseinheit (einem Objekt).

Dies ermöglicht es uns, die Komplexität zu kontrollieren, und es war ein ziemlich innovatives Konzept, als es entstand. Vergleichen Sie dies mit Dateien einerseits (reine Daten), Programmen, die diese Dateien andererseits lesen und verarbeiten (reine Logik) und ausgeben (wieder reine Daten).

Erst wenn Sie dieses Daten- und Logikpaket zusammen haben und eine reale Entität modellieren, können Sie Nachrichten austauschen, untergeordnete Klassen erstellen, private von öffentlichen Daten und Verhalten trennen, polymorphes Verhalten implementieren und all diese OO-spezifische Magie ausführen.

Also, ja, OO ist eine große Sache. Und nein, es ist nicht nur ein Haufen alter Sachen mit einem ausgefallenen Namen.

Alles auseinander zu nehmen, die Elemente zu betrachten und dann zu sagen "Oh, nun, hier gibt es nichts, was ich noch nie gesehen habe", bedeutet nicht, die Versammlung anzuerkennen, die die Innovation enthält. Das Ergebnis ist mehr als die Summe seiner Teile.

10
Martin Maat

Es gibt keine "offizielle" Definition der objektorientierten Programmierung, und vernünftige Leute sind sich nicht einig darüber, was die Qualität von OO tatsächlich definiert. Einige sagen Messaging, andere Subtypisierung, andere Vererbung, andere Datenbündelung und Verhalten. Das bedeutet nicht, dass der Begriff bedeutungslos ist, nur dass Sie nicht zu sehr in Streitereien darüber verwickelt werden sollten, was real OO] ist.

Kapselung und Modularität sind grundlegendere Prinzipien des Designs und sollten in allen Programmierparadigmen angewendet werden. Befürworter von OO behaupten nicht, dass diese Eigenschaften nur mit OO - nur das OO ist besonders gut geeignet) erreicht werden können Natürlich behaupten die Befürworter anderer Paradigmen wie der funktionalen Programmierung dasselbe für ihr Paradigma. In der Praxis sind viele erfolgreiche Sprachen Multiparadigmen, und die OO, funktionale usw. sollten eher als Werkzeuge als als der "einzig wahre Weg" angesehen werden ".

Ich denke, dass alle Prinzipien, die zur Verwaltung der Komplexität verwendet werden, durch prozedurale Programmiersprachen realisiert werden können.

Richtig, denn am Ende können Sie alles in jeder Programmiersprache tun. In einigen Sprachen ist es möglicherweise einfacher als in anderen, da alle Sprachen unterschiedliche Stärken und Schwächen haben.

8
JacquesB

Etwas, das die anderen Antworten nicht erwähnt haben: Zustand.

Sie sprechen von OO als Werkzeug zum Verwalten von Komplexität . Was ist Komplexität? Das ist ein unscharfer Begriff. Wir alle haben dies Wir können verstehen, was es bedeutet, aber es ist schwieriger, es genau zu bestimmen. Wir könnten die zyklomatische Komplexität messen, dh die Anzahl der Laufzeitpfade durch den Code, aber ich weiß nicht, worüber wir sprechen, wenn wir = verwenden OO zur Verwaltung der Komplexität.

Was ich denke , ist zustandsbezogene Komplexität.

Es gibt zwei Hauptideen hinter der Kapselung . Eine davon, das Ausblenden von Implementierungsdetails , wird in den anderen Antworten ziemlich gut behandelt. Aber ein anderer versteckt seinen Laufzeitstatus . Wir spielen nicht mit den internen Daten von Objekten herum. Wir übergeben Nachrichten (oder rufen Methoden auf, wenn Sie Implementierungsdetails dem Konzept vorziehen, wie Jörg Mittag betonte). Warum?

Die Leute haben bereits erwähnt, dass Sie die interne Struktur Ihrer Daten nicht ändern können, ohne den Code zu ändern, auf den zugegriffen wird, und Sie möchten dies an einer Stelle (der Zugriffsmethode) anstelle von 300 Stellen tun.

Aber es liegt auch daran, dass es schwierig ist, über den Code nachzudenken : prozeduraler Code (ob in einer Sprache, die prozeduraler Natur ist oder einfach in diesem Stil geschrieben ist ) bietet wenig Hilfe, um die Mutation des Staates einzuschränken. Alles kann sich jederzeit und überall ändern. Das Aufrufen von Funktionen/Methoden kann in der Ferne zu gruseligen Aktionen führen. Automatisierte Tests sind schwieriger, da der Erfolg der Tests durch den Wert nicht lokaler Variablen bestimmt wird, auf die allgemein zugegriffen werden kann.

Die beiden anderen großen Programmierparadigmen (OO und funktional) bieten interessante, aber fast diametral entgegengesetzte Lösungen für das Problem der zustandsbezogenen Komplexität. Bei der funktionalen Programmierung wird versucht, dies vollständig zu vermeiden: Funktionen sind im Allgemeinen rein, Operationen an Datenstrukturen geben Kopien zurück, anstatt das Original an Ort und Stelle zu aktualisieren usw.

OO bietet andererseits Tools an, um mit dem Verwalten des Status umzugehen (anstelle von Tools, um ihn zu vermeiden). Zusätzlich zu den Tools auf Sprachebene wie Zugriffsmodifikatoren (geschützt/öffentlich/privat), Getter und Setter usw. gibt es auch eine Reihe verwandter Konventionen wie das Demeter-Gesetz, das davon abrät, durch Objekte zu greifen, um an andere Objektdaten zu gelangen .

Beachten Sie, dass Sie keine Objekte benötigen, um dies wirklich zu tun: Sie könnten einen Abschluss haben, der unzugängliche Daten enthält und eine Datenstruktur von Funktionen an zurückgibt manipuliere es. Aber ist das nicht ein Objekt? Passt das nicht intuitiv zu unserer Vorstellung davon, was ein Objekt ist? Und wenn wir dieses Konzept haben, ist es nicht besser, es in der Sprache zu wiederholen, als sich (wie andere Antworten bereits sagten) auf eine kombinatorische Explosion konkurrierender Ad-hoc-Implementierungen zu verlassen?

7
Jared Smith

Benötigen wir wirklich OO Sprachen, um die Komplexität der Software zu verwalten?

Nr. Aber sie können in vielen Situationen helfen.

Ich habe jahrzehntelang hauptsächlich eine einzige OO Sprache verwendet, aber der größte Teil meines Codes ist eigentlich streng pro-OO-prozedural. Für alles, was eine GUI betrifft, verwende ich jedoch die umfangreiche OO Bibliothek der Sprache mit integrierten Methoden und Objekten, da dies meinen Code erheblich vereinfacht.

Beispielsweise erfordert eine Windows-Anwendung, die die ursprüngliche Windows-API auf niedriger Ebene zum Anzeigen eines Formulars, einer Schaltfläche und eines Bearbeitungsfelds verwendet, viel Code, während die Verwendung der Objektbibliotheken, die mit Visual Basic oder C # oder Delphi geliefert werden, dasselbe macht Programm winzig und trivial. Daher ist mein OO Code normalerweise relativ klein und für die GUI, während mein Code, den diese Objekte aufrufen, normalerweise viel größer ist und sich normalerweise nicht mit OO befasst (obwohl er je nach Typ variieren kann zu dem Problem, das ich zu lösen versuche).

Ich habe OO Programme gesehen, die übermäßig kompliziert waren, sich auf komplizierte esoterische Regeln für die Implementierung der Objekte stützten und viel einfacher hätten sein können, wenn sie ohne OO Konzepte geschrieben worden wären. Ich habe auch das Gegenteil gesehen: Komplexe Systeme, die nach der Implementierung und Vereinfachung durch die Verwendung von Objekten verlangen.

Wenn Sie Erfahrung sammeln, werden Sie feststellen, dass unterschiedliche Situationen unterschiedliche Tools und Lösungen erfordern und eine Größe nicht für alle geeignet ist.

5
joe snyder

Als jemand, der an einem sehr großen Projekt beteiligt ist, das vollständig in C geschrieben wurde, kann ich definitiv sagen, dass die Antwort ein klares "Nein" ist.

Modularität ist wichtig. Modularität kann jedoch in praktisch jeder anständigen Sprache implementiert werden. Beispielsweise unterstützt C die modulare Kompilierung, Header-Dateien und Strukturtypen. Dies reicht für 99% der Fälle aus. Definieren Sie ein Modul für jeden neuen abstrakten Datentyp, den Sie benötigen, und definieren Sie die Funktionen für die Bearbeitung des Datentyps. Manchmal möchten Sie Leistung und diese Funktionen befinden sich in der Header-Datei als Inline-Funktionen, manchmal verwenden Sie Standardfunktionen. Für den Benutzer ist alles unsichtbar, welcher Weg gewählt wird.

Strukturen unterstützen die Zusammensetzung. Beispielsweise können Sie eine gesperrte Hash-Tabelle haben, die aus einer Mutex-Sperre und einer regulären Hash-Tabelle besteht. Dies ist keine objektorientierte Programmierung; Es wird keine Unterklasse erstellt. Komposition ist ein Werkzeug, das viel älter ist als die Idee der objektorientierten Programmierung.

Für 1% der Fälle, in denen die Modularität auf Kompilierungsebene nicht ausreicht und Sie Laufzeitmodularität benötigen, gibt es eine Funktion namens Funktionszeiger. Sie ermöglichen individuelle Implementierungen einer genau definierten Schnittstelle. Beachten Sie, dass dies keine objektorientierte Programmierung in einer nicht objektorientierten Sprache ist. Dies definiert eine Schnittstelle und implementiert sie dann. Beispielsweise wird hier keine Unterklasse verwendet.

Betrachten Sie das vielleicht komplexeste Open Source-Projekt, das es gibt. Nämlich der Linux-Kernel. Es ist vollständig in der C-Sprache geschrieben. Dies erfolgt hauptsächlich mithilfe der Standard-Modularitätstools auf Kompilierungsebene, einschließlich der Komposition. Gelegentlich werden Funktionszeiger zum Definieren und Implementieren einer Schnittstelle verwendet, wenn zur Laufzeit Modularität erforderlich ist.

Wenn Sie versuchen, ein Beispiel für objektorientierte Programmierung im Linux-Kernel zu finden, ist es sicher sehr schwierig, ein solches Beispiel zu finden, es sei denn, Sie erweitern die objektorientierte Programmierung um Standardaufgaben wie "Definieren einer Schnittstelle und anschließende Implementierung".

Beachten Sie, dass auch die Programmiersprache C die objektorientierte Programmierung unterstützt, wenn Sie sie wirklich benötigen. Betrachten Sie beispielsweise das Toolkit für die grafische Benutzeroberfläche von GTK. Es ist tatsächlich objektorientiert, obwohl es in einer nicht objektorientierten Sprache geschrieben ist. Dies zeigt also, dass die Idee, dass Sie eine "objektorientierte Sprache" benötigen, zutiefst fehlerhaft ist. Es gibt nichts, was eine objektorientierte Sprache kann, was eine andere Art von Sprache nicht kann. Wenn Sie ein erfahrener Programmierer sind, wissen Sie außerdem sehr einfach, wie man objektorientierten Code in einer beliebigen Sprache schreibt. Es ist beispielsweise keine Belastung, C zu verwenden.

Die Schlussfolgerungen sind also, dass objektorientierte Sprachen wahrscheinlich nur für unerfahrene Programmierer nützlich sind, die nicht verstehen, wie das Konzept tatsächlich implementiert wird. Ich möchte jedoch nicht in der Nähe eines Projekts sein, in dem die Programmierer so unerfahrene Programmierer sind.

3
juhist

Der Grund für die Einführung von Programmierparadigmen, einschließlich objektorientierter Methoden, besteht darin, die Erstellung komplexerer und leistungsfähigerer Programme zu vereinfachen. In der August 1981-Ausgabe des Byte Magazine definierte Daniel Ingalls , einer der Hauptentwickler von Smalltalk, "objektorientiert" mit den folgenden Funktionen:

  • automatische Speicherverwaltung
  • fähigkeit zum Austausch von Nachrichten
  • eine einheitliche Metapher, die für alle Operationen der Sprache gilt
  • keine Komponente hängt von den Interna einer anderen Komponente ab (Modularität).
  • programm definiert nur das Verhalten von Objekten, nicht deren Darstellung (Polymorphismus)
  • jede Komponente sollte nur an einer Stelle erscheinen (Factoring)
  • die Verwendung einer virtuellen Maschine, die hardwareunabhängig ist
  • jede vom Benutzer zugängliche Komponente sollte zur Beobachtung und Kontrolle zur Verfügung stehen (reaktives Prinzip).
  • es sollte keinen Gesamtcontroller geben (kein Betriebssystem).

Dies waren die Prinzipien, die Ingalls als die von Xerox Parc Research entwickelten Überlegungen zum Fahrdesign für Smalltalk-80 identifizierte. In dem oben genannten Zeitschriftenartikel können Sie eine detaillierte Beschreibung jedes dieser Prinzipien lesen und wie sie zum objektorientierten Paradigma nach Ingalls beitragen.

Alle diese Prinzipien können mit jeder vollständigen Turing-Sprache angewendet werden, sei es prozedural, Assemblersprache oder was auch immer. Dies sind Gestaltungsprinzipien, keine Sprachspezifikation. Eine objektorientierte Sprache soll die Verwendung dieser Prinzipien beim Erstellen von Software erleichtern.

Um beispielsweise das erste von Ingalls Prinzipien (automatische Speicherverwaltung) zu übernehmen, kann jeder sein eigenes automatisches Speicherverwaltungssystem in einer prozeduralen Sprache schreiben, aber es wäre eine Menge Arbeit, dies zu tun. Wenn Sie eine Sprache wie Smalltalk oder Java mit integrierter automatischer Speicherverwaltung) verwenden, muss der Programmierer nicht so viel Arbeit mit der Speicherverwaltung leisten. Der Nachteil ist, dass der Programmierer weniger Kontrolle über das Programm hat Art und Weise, wie Speicher verwendet wird. Es gibt also einen Vor- und einen Nachteil. Die Idee eines Entwurfsparadigmas wie der objektorientierten Programmierung besteht darin, dass die Vorteile des Paradigmas die Nachteile zumindest für einige Programmierer überwiegen.

2
Tyler Durden

Dies ist eine sehr gute Frage, und ich bin der Meinung, dass die hier gegebenen Antworten nicht gerecht wurden. Deshalb werde ich meine Gedanken hinzufügen.

Das Ziel ist - Software-Komplexität verwalten . Das Ziel ist nicht "use OO language").

Dies ist kein Grund für die Einführung eines neuen Paradigmas. Es ist etwas, das natürlich passiert ist, als die Codierung reifer wurde. Es ist sinnvoller, Code zu schreiben, bei dem am Ende des Zuges ein Bus hinzugefügt wird (der Zug wird anhand einer verknüpften Liste modelliert), als am Ende der verknüpften Liste einen neuen Knoten hinzuzufügen.


Das Codieren in Bezug auf reale Entitäten ist einfach die offensichtliche und korrekte Art zu codieren, wenn wir über die realen Entitäten codieren.


Ein Computer kann mit dem Hinzufügen eines Knotens am Ende der verknüpften Liste genauso einfach arbeiten wie mit dem Hinzufügen eines zusätzlichen Busses am Ende des Zuges. Für Menschen ist es jedoch einfacher, mit Zug und Bus zu arbeiten als mit verknüpften Listen und Knoten, obwohl wir feststellen, dass der Zug mithilfe einer verknüpften Liste modelliert wird, wenn wir eine Ebene tiefer gehen.

Durch das Schützen oder Verschlüsseln der Dateien kann keine Kapselung erreicht werden. Das Gegenteil von Verschlüsselung ist Entschlüsselung. Das Gegenteil von Kapselung ist Dekapselung was bedeutet Zerlegung von Strukturen und Klassen in Programmiersprachen, um eine bessere Leistung zu erzielen. Die Leistung, die durch die Reduzierung des Speicherverkehrs und die Vermeidung von OOP Regelprüfungen. erzielt wurde

Daher können Sie Code schreiben, der sowohl verschlüsselt als auch gut gekapselt ist, da diese beiden Konzepte unterschiedlich sind.

Die Kapselung hilft bei der Bewältigung der Komplexität, da sie der Realität nahe kommt.

Programmieren Sie daher Objekte ein, da das Codieren für Sie einfacher und das Verständnis für Sie und alle anderen schneller ist.

0
displayName

Das einzige, woran Sie sich erinnern sollten, ist Folgendes:
Bei OOP geht es nicht um Sprachfunktionen; es geht um die Art und Weise, wie Sie Ihren Code strukturieren.

OOP ist eine Art zu denken und die Architektur Ihres Codes zu entwerfen. Sie kann in nahezu jeder Sprache ausgeführt werden. Dies schließt insbesondere die Nicht-OO-Sprachen auf niedriger Ebene ein, die als Assembler und C bezeichnet werden. Sie können in Assembler perfekt objektorientiert programmieren, und der in C geschriebene Linux-Kernel ist in vielerlei Hinsicht recht objektorientiert .

Das heißt, OO-Funktionen in einer Sprache reduzieren die Menge an Boilerplate-Code, die Sie schreiben müssen, um die gewünschten Ergebnisse zu erzielen, erheblich. Wenn Sie eine virtuelle Funktionstabelle explizit definieren und mit den entsprechenden Funktionszeigern in C füllen müssen, tun Sie in Java einfach nichts , und fertig . OO Sprachen entfernen einfach alles, was Cruft ermöglicht, aus dem Quellcode und verstecken es hinter Nizza, Abstraktionen auf Sprachebene (wie Klassen, Methoden, Mitglieder, Basisklassen, implizite Konstruktor-/Destruktoraufrufe usw.). ).

Also, nein, wir brauchen keine OO Sprachen, um OOP zu machen. Es ist nur das OOP ist so viel einfacher mit einer anständigen OO Sprache) zu tun.

Eine Möglichkeit zur Verwaltung der Softwarekomplexität besteht darin, das Framework vollständig von den gewünschten Aktionen zu trennen, indem ein Domain Specific Language verwendet wird. Dies bedeutet, dass sich die Ebene des Programmcodes von der Ebene unterscheidet, auf der die gewünschten Ergebnisse konfiguriert werden - eine völlig andere Sprache oder ein völlig anderes System. Wenn dies richtig gemacht wird, wird der herkömmliche Code im Wesentlichen zu einer Bibliothek, und der Benutzer oder eine andere Person, die die gewünschten Ergebnisse erstellt, verbindet die Dinge mit einer Skriptsprache oder einem visuellen Designtool, wie beispielsweise einem Berichtsgenerator.

Um zu funktionieren, muss eine strenge Grenze gezogen werden, welche Operationen möglich sind und wie sie miteinander verbunden sind (Skriptsprache oder visuelles Design, wie ein Formularkonstruktionswerkzeug). Metadaten sind eine wichtige Methode, um die Laufzeitkonfiguration von den Codierungsdetails zu abstrahieren, sodass ein System eine Vielzahl von gewünschten Ergebnissen unterstützen kann. Wenn die Grenzen festgelegt und eingehalten werden (wobei nicht jeder Antrag auf Erweiterung angenommen wird), können Sie ein langlebiges und robustes System haben, das für Menschen funktioniert, ohne dass sie Programmierer sein müssen, um das zu erreichen, was sie wollen.

Martin Fowler hat ein Buch darüber geschrieben, und die Technik ist fast so alt wie das Programmieren selbst. Man könnte fast sagen, dass alle Programmiersprachen domänenspezifische Sprachen sind, und daher ist die Idee endemisch und wird übersehen, weil sie so offensichtlich ist. Sie können jedoch weiterhin Ihre eigenen Skripte oder visuellen Design-Tools erstellen, um Ihnen das Leben zu erleichtern. Manchmal ist es viel einfacher, ein Problem zu verallgemeinern!

0
user251748