Brauchen wir wirklich OO-Sprachen, um die Komplexität der Software zu bewältigen?


209

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

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

So wie ich es verstehe, ist OOP eine Möglichkeit, die Komplexität von Software zu managen. Die Prinzipien sind jedoch nicht neu oder einzigartig, sondern in gewisser Weise universell für alle technischen Bereiche.

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

Den Grund für die Einführung eines neuen Programmierparadigmas verstehe ich jedoch nicht. Ich denke, dass alle Prinzipien, die zum Verwalten der Komplexität verwendet werden, durch prozedurale Programmiersprachen realisiert werden können. Zum Beispiel können wir das Programm aus Gründen der Modularität einfach in viele kleine Programme aufteilen, die genau definierte Aufgaben ausführen, deren Code in separaten Dateien enthalten ist. Diese Programme würden durch ihre wohldefinierte Eingabe und Ausgabe 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 nur aufrufen, wenn sie in neuen Programmen benötigt werden. Erfasst das nicht alles, was OOP ist, oder vermisse ich etwas sehr Offensichtliches?

Ich verlange keinen Beweis dafür, dass OOP mit Komplexität umgeht. Meiner Meinung nach schon. Aber ich denke, dass alle Prinzipien, die zur Verwaltung der Komplexität verwendet werden, wie Modularität, Kapselung, Verstecken von Daten usw., von prozeduralen Sprachen sehr einfach implementiert werden können. Warum also wirklich OOP, wenn wir ohne Komplexität auskommen?


41
Sie vermissen die Trennung von Schnittstelle und Implementierung. Die Möglichkeit, eine Implementierung zur Laufzeit gegen eine andere auszutauschen, ist ein sehr wichtiges Merkmal. Grundsätzlich wird dies durch die dynamische Methode des Dispatching von OO-Sprachen mit Vererbung erreicht. Prozedurale Sprachen können das auch, aber ohne Typensicherheit.
Marstato

81
Die Idee der objektorientierten Sprache und des objektorientierten Designs besteht weitgehend darin, diese universellen, intuitiven Konzepte so einfach wie möglich im Code darzustellen und neu zu erstellen. Wenn Sie ein Schema oder eine Reihe von Richtlinien hätten, wie all diese Dinge ohne eine inhärent objektorientierte Sprache erreicht werden können, dann würden Ihre Vorschläge zur Vorgehensweise effektiv die objektorientierte Methodik sein, die verwendet wird. Tatsächliche OO-Sprachen sind nur ein Weg, dies zu formalisieren und zu vereinfachen.
Standback

14
@RobbieDee hast du meine Frage tatsächlich gelesen? Es geht darum, OO auf einer grundlegenderen Ebene zu verstehen, indem das Wetter in Frage gestellt wird, bei dem die Softwarekomplexität ohne OO verwaltet werden kann. Ich versuche nicht, OO zu untergraben, ich versuche nicht, etwas Neues zu erfinden, ich versuche nur, es besser zu verstehen, und wenn die Frage so selbstverständlich ist, warum hat es die ausgezeichnete Antwort von Jörg erhalten?
Steakexchange

12
Das Verschlüsseln einer Datei ist keine Kapselung. Möglicherweise haben Sie den Inhalt des Codes von einem anderen Entwickler nicht gesehen, aber Sie haben nicht unbedingt das Innenleben des Codes vor anderem Code geschützt. Der ursprüngliche Autor könnte dies vor oder nach der Verschlüsselung tun, wenn er sich erinnern kann, wie.
JeffO

8
Sie brauchen nichts anderes als Maschinensprache - lassen Sie den Programmierer die Opcodes auswendig lernen und die Einsen und Nullen selbst schreiben. Aber eine Art "symbolische" Sprache ist sehr nützlich, um Fehler zu reduzieren und die Produktivität zu steigern, und wie Dijkstra bemerkte, hilft eine Sprache, die eine "Struktur" auferlegt (oder zumindest die Aufrechterhaltung der "Struktur" erleichtert), erheblich. OO-Sprachen sind angesichts des aktuellen Sprachniveaus möglicherweise nicht die ideale Technologie, aber für viele Anwendungen ziemlich gut. Die Idee ist, Komplexität zu managen, ohne sich in den Weg zu stellen.
Daniel R Hicks

Antworten:


177

Lass es mich mit einer wirklich niedrigen theoretischen Antwort versuchen :)

Was Sie wirklich fragen, ist: Warum sollte die Unterstützung der Objektorientierung direkt in die Sprache aufgenommen werden, wenn prozedurale Sprachen zum Entwerfen und Schreiben von OO-Code verwendet werden können?

Und die Antwort lautet: Einen Standard dafür zu haben, wie OO im Quellcode ausgedrückt wird, damit Sie nicht mit 22 verschiedenen Implementierungen für dieselbe Abstraktion enden.

Angenommen, ich erstelle ein MagicButtonund ein MagicSlider, das in einem Benutzeroberflächensystem verwendet werden kann. Ich brauche eine Möglichkeit, die Methoden, 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, zu gruppieren. Diese Objekte haben einige gemeinsame Methoden, da sie beide Magic-GUI-Objekte sind.

Ich kann die Gruppierung durchführen, indem ich Funktionen auf eine spezielle Art MagicSlider_DoSomething ...und Weise benenne , indem MagicSliderMethods.XXXich die Methoden in bestimmte Dateien einbinde, die auf eine spezielle Art und Weise benannt wurden , oder ich könnte eine andere spezielle Art und Weise finden, um dasselbe zu tun. Wenn es in der Sprache keinen Standard gibt, werde ich es anders machen als Sie und anders als alle anderen. Dies erschwert das Teilen von Code erheblich.

Ja, der späte Versand - virtuelle Methoden in OO-Sprachen - kann in prozeduralen Sprachen implementiert werden, aber es gibt so viele verschiedene Möglichkeiten, dies zu implementieren. Je nachdem, wer den Code geschrieben hat, werden Sie unterschiedliche Implementierungen von OO im selben Programm haben.

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: Mit den Abstraktionen in der Sprache können fortgeschrittene Code-Editoren wie Eclipse den Code statisch analysieren. Beispielsweise 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 basierend auf den von Ihnen erweiterten Klassen und den von Ihnen implementierten Schnittstellen implementieren muss. Dies wäre fast unmöglich, wenn es keinen Sprachstandard für OO gäbe.


40
Klassisches Beispiel: Lua. Es ist nicht von Haus aus OO, kann aber geändert werden. Dies bedeutet, dass es ungefähr 5 verschiedene, gleichermaßen bekannte OO-Bibliotheken gibt, die nicht vollständig interoperabel sind.
Kroltan

55
@steakexchange Du konzentrierst dich absolut zu sehr auf. Sehr wenig hat einen "alleinigen Zweck". Alle Sprachen erledigen viele verschiedene Dinge in unterschiedlichem Maße. Wenn Sie sich für eine Sprache entscheiden, wählen Sie die Kompromisse aus, die am besten zu dem Zweck passen, für den Sie sie benötigen.
Tim B

42
@nocomprende Abstraktionen zu standardisieren ist fast wörtlich das, wofür Programmiersprachen gedacht sind. Sogar die Assemblersprache abstrahiert über die Unterschiede von etwa zehn Hardwaregenerationen in anderthalb Jahrzehnten.
David Moles

56
@DavidMoles Standardisierte Abstraktionen sind buchstäblich was Programmiersprachen sind. Verpassen Sie nicht die perfekte Gelegenheit, "buchstäblich" zu verwenden!
Clement Cherlin

12
Es ist möglich, dies zu standardisieren. Als ich Mitte der 90er Jahre an der Uni war, habe ich ziemlich viel in X-Windows gearbeitet (hauptsächlich basierend auf Motif für diejenigen, die sich an solche Dinge erinnern). Mit X-Windows konnten Sie tatsächlich alle Funktionen der Objektorientierung in regulärem C implementieren . Die mentale Gymnastik dazu war jedoch ziemlich umfangreich und stützte sich stark auf Leute, die nicht in die Kiste schauten (zu diesem Zeitpunkt endete Schrödingers Widget-Code im Allgemeinen tot). OO-Sprachen verbergen dies vor Programmierern, so wie es ein regulärer Compiler für Assembler tut, und das Leben ist einfacher.
Graham

211

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

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

Wenn Sie also der Meinung sind, dass OO genau das ist, dann ist Ihre Schlussfolgerung richtig: Sie können all dies in prozeduralen Sprachen tun , weil sie nichts mit OO zu tun haben .

Eine der bahnbrechenden Arbeiten zum Thema Modularität befasst sich beispielsweise mit den Kriterien für die Zerlegung von Systemen in Module . Es gibt dort keine Erwähnung von OO. (Es wurde 1972 geschrieben, bis dahin war OO immer noch eine dunkle Nische, obwohl es bereits mehr als ein Jahrzehnt alt war.)

Während Datenabstraktion in OO wichtig ist, ist sie eher eine Folge der Hauptfunktion von OO (Messaging) als eine definierende Funktion. Es ist auch sehr wichtig, sich daran zu erinnern, dass es verschiedene Arten der Datenabstraktion gibt. Die beiden am häufigsten verwendeten Arten der Datenabstraktion (wenn wir "überhaupt keine Abstraktion" ignorieren, die wahrscheinlich immer noch häufiger verwendet wird als die beiden anderen zusammen) sind abstrakte Datentypen und Objekte . Wenn Sie also "Information Hiding", "Encapsulation" und "Data Abstraction" sagen, haben Sie nichts über OO gesagt, da OO nur eine Form der Datenabstraktion ist und die beiden sich in der Tat grundlegend unterscheiden:

  • Bei abstrakten Datentypen ist der Mechanismus für die Abstraktion das Typensystem . Es ist das Typsystem, das die Implementierung verbirgt. (Das Typensystem muss nicht unbedingt statisch sein.) Bei Objects ist die Implementierung hinter einer prozeduralen Schnittstelle verborgen , für die keine Typen erforderlich sind. (Zum Beispiel kann es mit Closures implementiert werden, wie es in ECMAScript gemacht wird.)
  • Bei abstrakten Datentypen sind Instanzen verschiedener ADTs voneinander gekapselt, Instanzen desselben ADT können jedoch die Darstellung und die private Implementierung des jeweils anderen prüfen und auf diese zugreifen. Objekte sind immer von allem gekapselt . 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 können das tun. Keine .

Dies bedeutet im Übrigen, dass Klassen in Java nicht objektorientiert sind. Zwei Instanzen derselben Klasse können auf die Repräsentation und die private Implementierung des jeweils anderen zugreifen. Daher sind Instanzen von Klassen keine Objekte, sondern ADT-Instanzen. Java interfaces, aber sie bieten objektorientierte Datenabstraktion. Mit anderen Worten: Nur Instanzen von Interfaces sind Objekte in Java, Instanzen von Klassen nicht.

Grundsätzlich können Sie für Typen nur Schnittstellen verwenden. Dies bedeutet, dass Parametertypen von Methoden und Konstruktoren, Rückgabetypen von Methoden, Typen von Instanzfeldern, statischen Feldern und lokalen Feldern, das Argument für einen instanceofOperator oder einen Umwandlungsoperator und die Typargumente für einen generischen Typkonstruktor immer Schnittstellen sein müssen. Eine Klasse darf nur direkt nach dem newOperator verwendet werden, nirgendwo anders.

Zum Beispiel können wir das Programm aus Gründen der Modularität einfach in viele kleine Programme aufteilen, die genau definierte Aufgaben ausführen, deren Code in separaten Dateien enthalten ist. Diese Programme würden durch ihre wohldefinierte Eingabe und Ausgabe 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 nur aufrufen, wenn sie in neuen Programmen benötigt werden. Erfasst das nicht alles, was OOP ist, oder vermisse ich etwas sehr Offensichtliches?

Was Sie beschreiben, ist OO.

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

Bei der Objektorientierung dreht sich alles um Messaging (auch bekannt als dynamischer Versand ). Der Begriff "Objektorientiert" wurde von Dr. Alan Kay, dem Hauptdesigner von Smalltalk, geprägt und definiert ihn folgendermaßen :

OOP bedeutet für mich nur Nachrichtenübermittlung, lokale Aufbewahrung und Schutz sowie das Verstecken von staatlichen Prozessen und extrem spätes Binden aller Dinge.

Lassen Sie uns das zusammenfassen:

  • Messaging ("Versand virtueller Methoden", wenn Sie nicht mit Smalltalk vertraut sind)
  • Staats-Prozess sollte sein
    • vor Ort aufbewahrt
    • 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 zur Entwurfszeit nicht wissen, was Sie aufrufen werden, sodass Sie keine Annahmen über die konkrete Darstellung des Status treffen können. Eigentlich geht es also um Messaging. Late-Binding ist eine Implementierung von Messaging, und Encapsulation ist eine Folge davon.

Später stellte er klar, dass " die große Idee" Messaging "ist, und bedauert, sie" objektorientiert "statt" nachrichtenorientiert "genannt zu haben, weil der Begriff" objektorientiert "den Fokus auf das Unwichtige (Objekte) legt ) und lenkt von dem ab, was wirklich wichtig ist (Messaging):

Nur eine sanfte Erinnerung daran, dass ich bei der letzten OOPSLA einige Anstrengungen unternommen habe, um alle daran zu erinnern, dass Smalltalk nicht nur NICHT seine Syntax oder die Klassenbibliothek ist, sondern nicht einmal Klassen. Es tut mir leid, dass ich den Begriff "Objekte" für dieses Thema vor langer Zeit 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 bei 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 Entwicklung großartiger und erweiterbarer Systeme liegt vielmehr in der Gestaltung der Kommunikation der Module als in der Festlegung der 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 bestimmten Standard hinausgehen, und (b) ein unterschiedliches Maß an sicherer Interoperabilität zwischen diesen Ideen ermöglichen.

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

Messaging ist für OO sowohl als Metapher als auch als Mechanismus von grundlegender Bedeutung .

Wenn Sie jemandem eine Nachricht senden, wissen Sie nicht, was er damit macht. Das einzige, was Sie beobachten können, ist ihre Antwort. Sie wissen nicht, ob sie die Nachricht selbst verarbeitet haben (dh ob das Objekt eine Methode hat), ob sie die Nachricht an eine andere Person weitergeleitet haben (Delegation / Proxying) oder ob sie sie überhaupt verstanden haben. Darum geht es bei der Verkapselung, 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 "moderner" Begriff für "Messaging" ist "dynamischer Methodenversand" oder "virtueller Methodenaufruf", der jedoch die Metapher verliert und sich auf den Mechanismus konzentriert.

Es gibt also zwei Möglichkeiten, die Definition von Alan Kay zu betrachten: Wenn Sie sich die Definition einzeln ansehen, stellen Sie möglicherweise fest, dass Messaging im Grunde genommen ein späteingebundener Prozeduraufruf ist und eine späte Bindung eine Verkapselung impliziert und # 2 sind eigentlich überflüssig, 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: Nachrichtenversenden ist verspätet. Wenn Messaging das einzig mögliche wäre, dann wäre # 3 trivial wahr: Wenn es nur eine Sache gibt und diese Sache verspätet gebunden ist, dann sind alle Dinge verspätet gebunden. Die Verkapselung ergibt sich wiederum aus dem Messaging.

Ähnliche Punkte finden sich auch in On Understanding Data Abstraction, überarbeitet von William R. Cook, und in seinem Vorschlag für vereinfachte, moderne Definitionen von "Objekt" und "objektorientiert" :

Der dynamische Versand von Vorgängen 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, es sei denn, sie wird ausgeführt. Dies ist genau das gleiche wie bei erstklassigen Funktionen, die immer dynamisch abgesetzt werden.

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

Benjamin Pierce in Types and Programming Languages argumentiert, dass das bestimmende Merkmal der Objektorientierung die offene Rekursion 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 eigentlich 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 so), oder mit anderen Worten, Messaging.

Wie Sie sehen, 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 rigorose mathematische Sicht. Aber das Wichtige ist: Der Philosoph, der Pragmatiker und der Theoretiker sind sich einig! Messaging ist die eine 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 Delegation sein. Tatsächlich wird im Vertrag von Orlando die Delegation als Alternative zur Vererbung erörtert und wie unterschiedliche Formen der Delegation und Vererbung zu unterschiedlichen Entwurfspunkten im Entwurfsraum objektorientierter Sprachen führen. (Beachten Sie, dass die Leute auch in Sprachen, die Vererbung unterstützen, wie Java, tatsächlich lernen, dies zu vermeiden, was wiederum darauf hinweist, dass dies für OO nicht erforderlich ist.)


16
+100 - Wir geben den Dingen die inhärente Schuld, weil sie unsachgemäß verwendet werden.
JeffO

55
Sorry, aber das ist so unglaublich falsch. Alan Kay mag auf den Begriff gekommen sein, aber die Prinzipien gab es schon vor Smalltalk. Die objektorientierte Programmierung stammt von Simula, und ihr OO-Stil hatte nichts mit "Nachrichten" zu tun. Nahezu jede OO-Sprache, die erfolgreich war, basiert auf den in Simula festgelegten Grundprinzipien - die gleichen, die wir in Java sehen - und OO im Smalltalk-Stil war bei jeder Wiedereinführung ein Fehlschlag auf dem "Marktplatz der Ideen". weil es einfach nicht sehr gut funktioniert. Der Name war das einzig wirklich Bedeutsame, was Kay beigesteuert hat.
Mason Wheeler

23
@steakexchange Nein. "Die Essenz von OO", das, was es wirklich auszeichnet, sind Objekte mit virtuellen Methoden. Es gibt einen Grund, warum niemand Smalltalk verwendet: Das Nachrichtenübermittlungssystem funktioniert auf Einzelrechnerskalen sehr schlecht. Jedes Mal, wenn ein gut gemeinter, aber naiver Sprachdesigner versucht, Smalltalk-Prinzipien neu zu implementieren, schlägt dies fehl. (Das jüngste Beispiel wäre Objective-C, das niemand jemals verwendet hätte, wenn Steve Jobs es nicht der gesamten iOS-Community in die Kehle gedrückt hätte. Es hat außerhalb des Apple-Ökosystems keine Anziehungskraft gefunden, und es gibt einen Grund dafür.) )
Mason Wheeler

28
@MasonWheeler Könnten Sie vielleicht Ihren Kommentar in einer Antwort näher erläutern, da Sie eine ganz andere Meinung haben als Jörg?
Steakexchange

20
Es ist auch erwähnenswert, dass sich das Konzept der objektorientierten Sprachen stark weiterentwickelt hat. Diese überlieferten Konzepte mögen heutzutage nicht mehr so ​​wahr sein, da viele Sprachen die alten Modelle hinter sich lassen und Multiparadigmen einbeziehen. Schauen Sie sich zum Beispiel C # an - diese Sprache vermischt fast alles auf einmal und obwohl sie meistens als OO-Sprache bezeichnet wird, ist sie tatsächlich eine Mischung aus verschiedenen Paradigmen. Das macht es zu einem wirklich aussagekräftigen Werkzeug für Entwickler in aller Welt. Class-Based OO ist eine von vielen gleichermaßen gültigen Varianten der OO-Programmierung.
T. Sar

66

Aber ich denke, dass alle Prinzipien, die zur Verwaltung der Komplexität verwendet werden, wie Modularität, Kapselung, Verstecken von Daten usw., von prozeduralen Sprachen sehr einfach implementiert werden können.

Wenn Sie "sehr leicht" sagen, geben Sie eine sehr mutige Aussage ab. Ich lese es so: "Ich sehe die Schwierigkeit nicht, sie darf also nicht sehr groß sein." Wenn Sie das so formulieren, wird klar, dass Sie nicht fragen: "Warum brauchen wir OO?", Sondern: "Warum sind die Schwierigkeiten, auf die andere Programmierparadigmen gestoßen sind, die zur Erfindung von OO geführt haben, für mich nicht sofort ersichtlich?" "

Eine Antwort auf diese Frage ist, dass viele dieser Schwierigkeiten bei den Programmen, an denen Sie arbeiten, nicht existieren. 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 der Arten von Spielzeugprogrammen, mit denen wir CS-Studenten beauftragt sind, können wir sie genauso gut in BASIC oder Assembly schreiben wie Java oder Python. Das liegt daran, dass die inhärente Komplexität der Aufgaben so gering ist, dass es nur einen Entwickler gibt, keine älteren Interoperabilitätsprobleme gibt, die Leistung keine Rolle spielt und der Code wahrscheinlich immer nur eine Handvoll Mal auf einem Computer ausgeführt wird.

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

Stellen Sie sich jetzt denselben Studenten und dasselbe Fahrzeug vor, wie sie auf einem leeren Parkplatz im Schritttempo fahren. Sie sind in Ordnung, weil ihr Können der Aufgabe angemessen ist. Es besteht kein Druck, es besteht nur ein geringes Risiko, und sie können die einzelnen Teilaufgaben Anfahren, Erfassen, Schalten, Beschleunigen und Lenken 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. Wir sind jedoch nicht alle Profifahrer in Topform, und wir möchten in der Regel, dass die Konstrukteure des Autos sich um all diese Komplexität kümmern.

Ein erfahrener, disziplinierter Programmierer kann in der Tat ein funktionierendes System mit hoher Komplexität in C oder Assembly erstellen. Aber wir sind nicht alle Linus Torvalds. Wir sollten es auch nicht 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 überhaupt auf das vorliegende Problem eingehen kann. Wenn ich eine Sprache nutzen kann, die Lösungen für bereits gelöste Probleme enthält, warum sollte ich das dann nicht tun?

Also werde ich Ihre Frage umdrehen und Sie fragen, warum wir sie nicht verwenden sollten, wenn Sprachen praktische Funktionen wie Verkapselung und Polymorphismus bieten?


13
Grundsätzlich ist es also möglich, OO mit einer prozeduralen Sprache durchzuführen, dies geschieht jedoch manuell, indem eine standardisierte OO-Sprache verwendet wird, die automatisiert und vereinfacht wird.
Steakexchange

6
@steakexchange Ziemlich genau das.
Tim B

3
@steakexchange Ein gutes historisches Beispiel dafür war früher das Objektmodell für X Windows. Es wurde in C geschrieben, basierte jedoch auf einem objektorientierten System. Sie mussten also bestimmte Konventionen befolgen, um mit dem Unterricht in Kontakt zu treten, damit Ihre Klassen mit den Konventionen aller anderen gut mithalten konnten.
Ukko

7
Sicherlich. Aber man könnte ein Computer nicht mehr booten , indem Sie Raw Disk schreibt , anstatt sich auf das Dateisystem machen, und es wird in einer Ad-hoc - Objekt - System von einem Anfänger gebaut , um Probleme mit wirklich schwierig sein. Wenn die Verkapselung korrekt durchgeführt wird, verhindern Sie, dass wir uns absichtlich oder unbeabsichtigt in Dinge einmischen, die wir nicht sollten.
Clement Cherlin

3
Es ist für mich interessant, dass die Beispiele, die Sie für Anwendungen nennen, die von OO profitieren würden, häufig nicht in OO-Sprachen geschrieben sind. Die 40 Jahre alten Spaghetti sind wahrscheinlich in C, COBOL, FORTRAN oder REXX geschrieben. Der Anzeigemanager ist wahrscheinlich in C geschrieben (wenn auch mit OO-Konventionen), und viele erfolgreiche verteilte Multithread-Systeme sind in Erlang, Go oder C geschrieben.
James_pic

22

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

Erstens ist es erwähnenswert, dass es keine einheitliche Definition von OOP gibt, so dass es Menschen geben kann, die mit dem, was ich als OOP bezeichne, 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.

Es gibt jedoch einige Möglichkeiten, wie OOP differenzierter ist als das, was Sie gesagt haben:

  • Kapselung: Es geht nicht nur darum, eine festgelegte Schnittstelle für ein Modul (dh Abstraktion) zu haben, sondern auch 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 mehrere Dinge zur Umsetzung dieser Schnittstelle machen, und Sie können in einem hierarchischen Weg , dies zu tun, bestimmte Teile ihrer Umsetzung zu verändern, während erben all bisherigen Teile, massiv Code - Duplizierung zu reduzieren.

    Wenn Sie in den 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 : Nachdem Sie eine Schnittstelle definiert haben, sollte alles, was diese Schnittstelle verwendet, vom Standpunkt der verfügbaren Operationen nicht unterscheidbar sein, und Sie sollten nicht wissen müssen, welche Implementierung für die Verwendung einer Schnittstelle verwendet wird. Hier kommt es auf die Subtypisierung und das Liskov-Substitutionsprinzip an .

  • Kopplung : Ein Schlüsselaspekt von OOP ist, dass wir die Dinge eng mit denselben Operationen verknüpfen und die verschiedenen Formen, die sie haben können, ausbreiten. Daten werden mit Operationen an diesen Daten gebündelt. Dies bedeutet, dass es sehr einfach ist, eine neue Form von Daten hinzuzufügen (eine neue Implementierung), aber es sehr schwierig ist, einer Schnittstelle eine neue Operation hinzuzufügen (da Sie jede Klasse aktualisieren müssen, die die Schnittstelle implementiert). Dies steht im Gegensatz zu algebraischen Datentypen in funktionalen Sprachen, in denen es sehr einfach ist, eine neue Operation hinzuzufügen (Sie schreiben nur eine Funktion, die alle Fälle behandelt), aber es ist schwierig, eine neue Variante hinzuzufügen (da Sie eine neue hinzufügen müssen) Fall für alle Ihre Funktionen).


1
Gute Antwort! Ein Teil, dem ich nicht zustimme: Die Unterscheidung, die Sie über die Verkapselung treffen, ist ungültig. Kapselung bedeutet immer, "den Zugriff über diese Schnittstelle hinaus zu verbieten" - das gilt für OOP- und Nicht-OOP-Einstellungen gleichermaßen. Dieser Teil ist also nicht wirklich einzigartig für OOP.
DW

@DW Ich habe versucht, dies zu klären, und nicht gesagt, dass es nur für OOP gilt, sondern dass es den Unterschied zwischen Kapselung und Abstraktion gibt. Danke für die Rückmeldung!
jmite

2
OKAY. Aber ich habe immer noch eine andere Meinung darüber, was hier zu diesem Thema geschrieben steht. Sie haben geschrieben, dass "OOP in gewisser Weise nuancierter ist als das, was Sie gesagt haben", aber Kapselung ist keine Möglichkeit, dass OOP nuancierter ist als das, was in der Frage geschrieben wurde. Einkapselung ist das, was es ist, in jedem Paradigma. Und wo Sie geschrieben haben, dass "Was Sie beschreiben, ist nicht OOP, es ist Abstraktion", dachte ich, dass die ursprüngliche Frage die Verkapselung (nicht nur Abstraktion) zu beschreiben versuchte. Ich denke, ich lasse diesen Kommentar einfach aus einer anderen Perspektive. Ich denke die Antwort ist sehr hilfreich!
DW

Vererbung ist ein gemeinsames Merkmal, das jedoch mehreren wichtigen OO-Sprachen fehlt.
Bradd Szonye

Gute Antwort, aber IMO übertreiben Sie das Autobeispiel. Ein Motor für ein bestimmtes Modell verfügt über eine genau definierte Schnittstelle (Nockenwelle, Halterungsbuchsen usw.). Sie können einen normalen alten Vergaser durch einen mit Kraftstoffeinspritzung ersetzen, einen Turbolader usw. hinzufügen, ohne das Getriebe zu beeinträchtigen. (Obwohl für einen Dieselmotor ein modifizierter Kraftstofftank IIRC erforderlich ist.) Umgekehrt können Sie ein Schaltgetriebe durch ein Automatikgetriebe und ein AFAIK ersetzen, die den Motor überhaupt nicht beeinflussen.
David

11

Brauchen wir wirklich OO-Sprachen, um die Komplexität der Software zu bewältigen?

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

Wenn "brauchen" bedeutet erfordert, nein, wir benötigen 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 Funktionalität an Daten.

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

Aber dann werden Sie wahrscheinlich mit Datenkonstellationen enden, die zusammenpassen, und Sie werden beginnen, Tupel, Datensätze oder Datenwörterbücher weiterzugeben.

Und das sind wirklich alle Methodenaufrufe: Teilfunktionen für gebundene Datensätze.

Merkmal für Merkmal

Eigenschaften von OOP:

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

Keines dieser Dinge ist 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 Programmiererproduktivität erzielen. Dies ist eine kontroverse Feststellung, und einige Forscher geben an, dass sie diese Produktivitätsgewinne unter bestimmten Bedingungen nicht reproduzieren können. (Quelle)

Fazit

Wir brauchen keine OOP. Aber in einigen Fällen möchte der Benutzer OOP.

Mein Verständnis ist, dass ausgereifte 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 sehr schnell produktiv werden.


10

Ich werde versuchen, mich kurz zu fassen.

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

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

Erst wenn Sie dieses Paket aus Daten und Logik zusammen haben und eine reale Entität modellieren, können Sie mit dem Austausch von Nachrichten beginnen, untergeordnete Klassen erstellen, private und öffentliche Daten und Verhaltensweisen trennen, polymorphes Verhalten implementieren und all diese OO-spezifischen magischen Aufgaben ausführen.

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

Wenn man alles auseinander nimmt, die Elemente betrachtet und dann sagt "Oh, nun, hier gibt es nichts, was ich noch nie gesehen habe", erkennt man die Baugruppe nicht, in der sich die Innovation befindet. Das Ergebnis ist mehr als die Summe seiner Teile.


8

Es gibt keine "offizielle" Definition der objektorientierten Programmierung, und vernünftige Leute sind sich nicht einig darüber, was eigentlich die Qualität von OO definiert. Einige sagen Messaging, andere sagen Subtyping, andere sagen Vererbung, manche sagen die Bündelung von Daten und Verhalten. Das bedeutet nicht, dass der Begriff bedeutungslos ist, nur, dass Sie nicht zu sehr darüber streiten sollten, was echte 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 erreicht werden können - nur, dass OO dafür besonders gut geeignet ist. Natürlich behaupten die Befürworter anderer Paradigmen wie etwa funktionale Programmierung dasselbe für ihr Paradigma. In der Praxis sind viele erfolgreiche Sprachen ein Multiparadigma, und das OO, das Funktionale usw. sollte eher als Werkzeug als als der "einzig wahre Weg" angesehen werden.

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

Stimmt, denn am Ende kann man in jeder Programmiersprache alles machen. In einigen Sprachen ist es möglicherweise einfacher als in anderen, da alle Sprachen unterschiedliche Stärken und Schwächen haben.


7

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 verschwommener Begriff. Wir alle haben dieses Gefühl dafür, was es bedeutet, aber es ist schwieriger, es festzuhalten. 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 OO zum Verwalten der Komplexität verwenden.

Ich denke, wir sprechen von staatlicher Komplexität.

Hinter der Verkapselung stehen zwei Hauptideen . Eine davon, das Verbergen von Implementierungsdetails , ist in den anderen Antworten ziemlich gut abgedeckt. Aber ein anderer versteckt seinen Laufzeitzustand . Wir spielen nicht mit den internen Daten von Objekten herum. Wir leiten Nachrichten weiter (oder rufen Methoden auf, wenn Sie Implementierungsdetails dem Konzept vorziehen, wie Jörg Mittag hervorhob). Warum?

Die Leute haben es bereits erwähnt, weil 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.

Das liegt aber auch daran, dass es schwierig ist, über den Code nachzudenken : Der prozedurale Code (ob in einer prozeduralen Sprache oder einfach so geschrieben) bietet wenig Hilfe, um die Mutation des Staates einzuschränken. Alles kann sich jederzeit und überall ändern. Das Aufrufen von Funktionen / Methoden kann aus der Ferne unheimlich sein. Automatisiertes Testen ist schwieriger, da der Erfolg der Tests durch den Wert nicht lokaler Variablen bestimmt wird, auf die häufig zugegriffen wird.

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 gänzlich 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 hingegen bietet Tools für den Umgang mit dem Verwaltungsstatus (anstelle von Tools zur Vermeidung). Zusätzlich zu den Tools auf Sprachebene wie Zugriffsmodifikatoren (geschützt / öffentlich / privat), Gettern und Setzern usw. gibt es auch eine Reihe verwandter Konventionen wie das Gesetz von Demeter, die davon abraten, durch Objekte zu greifen, um an andere Objekte Daten zu gelangen .

Beachten Sie, dass Sie nicht brauchen Objekte zu tun wirklich etwas davon: Sie einen Verschluss haben könnte , die unzugänglichen Daten hat und gibt eine Datenstruktur von Funktionen , die es zu manipulieren. Aber ist das nicht ein Objekt? Passt das nicht zu unserer Vorstellung davon, was ein Objekt ist, intuitiv? Und wenn wir dieses Konzept haben, ist es dann nicht besser, es in der Sprache zu wiederholen, als sich (wie andere Antworten sagten) auf eine kombinatorische Explosion konkurrierender Ad-hoc-Implementierungen zu verlassen?


5

Brauchen wir wirklich OO-Sprachen, um die Komplexität der Software zu bewältigen?

Nein, 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 tatsächlich streng prozedural vor OO. Für alles, was eine grafische Benutzeroberfläche betrifft, verwende ich 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 in Visual Basic oder C # oder Delphi enthalten sind, dasselbe bewirkt Programm winzig und trivial. Daher ist mein OO-Code in der Regel relativ klein und für die GUI gedacht, während mein Code, den diese Objekte aufrufen, in der Regel viel größer ist und sich normalerweise nicht darum kümmert, OO zu sein (obwohl er je nach dem zu lösenden Problem variieren kann).

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 wären, wenn sie ohne OO-Konzepte geschrieben worden wären. Ich habe auch das Gegenteil gesehen: Komplexe Systeme, die darauf bedacht sind, mithilfe von Objekten neu implementiert und vereinfacht zu werden.

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


3

Als jemand, der an einem sehr großen Projekt beteiligt ist, das vollständig in C geschrieben ist, 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 ist für 99% der Fälle ausreichend. 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 sind in der Header-Datei als Inline-Funktionen, ein anderes Mal verwenden Sie Standardfunktionen. Es ist alles für den Benutzer 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 die 1% der Fälle, in denen die Modularität der Kompilierungsebene nicht ausreicht und Sie Laufzeitmodularität benötigen, gibt es einen sogenannten 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 den Linux-Kernel. Es ist vollständig in der C-Sprache geschrieben. Dies geschieht hauptsächlich unter Verwendung der Standard-Modularitätstools auf Kompilierungsebene, einschließlich Komposition, und gelegentlich, wenn Laufzeitmodularität erforderlich ist, werden Funktionszeiger zum Definieren und Implementieren einer Schnittstelle verwendet.

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 selbst die Programmiersprache C die objektorientierte Programmierung unterstützt, wenn Sie sie wirklich benötigen. Betrachten Sie beispielsweise das GTK-Toolkit für grafische Benutzeroberflächen. Es ist tatsächlich objektorientiert, obwohl es in einer nicht objektorientierten Sprache geschrieben ist. Dies zeigt also, dass die Vorstellung, dass Sie eine "objektorientierte Sprache" benötigen, zutiefst fehlerhaft ist. Es gibt nichts, was eine objektorientierte Sprache nicht kann. Wenn Sie ein erfahrener Programmierer sind, können Sie außerdem sehr einfach objektorientierten Code in einer beliebigen Sprache schreiben. Zum Beispiel ist die Verwendung von C keine Belastung.

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, bei dem die Programmierer so unerfahrene Programmierer sind.


1
"[...] die Schlussfolgerungen sind, dass objektorientierte Sprachen wahrscheinlich nur für unerfahrene Programmierer nützlich sind, die nicht verstehen, wie das Konzept tatsächlich umgesetzt wird." Interessant. Welche Sprachen haben Sie im Sinn? Haben Sie Beispiele für Open Source-Projekte, die in diesen Sprachen geschrieben wurden und fehlgeschlagen sind oder nicht?
Vincent Savard

3
Sie sprechen einige gute Punkte an, aber Ihre Hauptidee ist fehlerhaft. Ja, es ist möglich, OO-Konzepte wie Kapselung, virtueller Versand, Vererbung und sogar Garbage Collection in einer Sprache wie C zu implementieren. Dies ist auch in Assemblys möglich. Die Programmierung wird dadurch nicht einfacher. Das Programmieren und insbesondere das Entwerfen in einer Sprache wie C ist definitiv schwieriger als in einer OO-Sprache. In C müssen Sie die Konzepte ihrer Implementierung zuordnen, in einer OO-Sprache müssen Sie diesen Schritt nicht ausführen (zumindest nicht für die OO-Konzepte).
fishinear

1
"[Funktionszeiger] ermöglichen die individuelle Implementierung 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." Sorry, aber das ist völlig falsch, denn genau das ist OOP. "Beispielsweise wird hier keine Unterklasse verwendet" Die Unterklasse ist keine erforderliche Funktion von OOP. Beachten Sie beispielsweise, dass JavaScript eine objektorientierte Sprache ist, die keine Unterklassen (oder überhaupt Klassen) aufweist. Nur Objekte, die Funktionsreferenzen enthalten.
Jules

1
Um meinen letzten Kommentar zu verdeutlichen, ist mein Punkt, dass der Hauptunterscheidungsfaktor zwischen OOP (nicht notwendigerweise eine bestimmte OO-Sprache) und anderen Methoden darin besteht, dass wir in OOP Schnittstellen definieren, die abstrakt mit Daten arbeiten, ohne das Format dieser Daten kennen zu müssen Binden der Implementierung der Schnittstellen an die Daten selbst. Das ist was OOP ist. Die Methode der Implementierung spielt keine Rolle, ob es sich um eine Java-Stilklasse, ein JavaScript-Objekt (dh eine Zuordnung von Name zu Attribut, bei der es sich entweder um Daten oder Code handeln kann) oder eine Struktur mit Funktionszeigern und einer Leerstelle * für die Daten handelt.
Jules

1
"Die Schlussfolgerungen sind also, dass objektorientierte Sprachen wahrscheinlich nur für Programmieranfänger nützlich sind, die nicht verstehen, wie das Konzept tatsächlich umgesetzt wird." Ich weiß ziemlich genau, wie diese Konzepte umgesetzt werden. Ich habe genug damit gearbeitet, um auch kompetent zu sein. Ich habe in der Vergangenheit sogar einen Interpreter und einen Compiler für OO-Sprachen implementiert. Aber weil ich lieber in höheren Sprachen mit erstklassigen Objekten arbeite, muss ich ein Anfänger sein, mit dem Sie lieber nicht arbeiten möchten ?!
Jules

2

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-Magazins 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 Repräsentation (Polymorphismus)
  • Jede Komponente sollte nur an einer Stelle erscheinen (Factoring)
  • die Verwendung einer virtuellen Maschine, die hardwareunabhängig ist
  • Jede für den 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 Überlegungen zum Fahrdesign für SmallTalk-80 identifizierte, wie sie von Xerox Parc Research entwickelt wurden. In dem oben genannten Magazinartikel können Sie eine detaillierte Beschreibung der einzelnen Prinzipien lesen und erfahren, wie sie zu dem objektorientierten Paradigma nach Ingalls beitragen.

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

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


Ich denke, dass die gleichen Regeln für domänenspezifische Sprachen gelten würden. Gleiche Vor- und Nachteile ... Der einzige Unterschied besteht darin, dass DSLs so einfach gestaltet werden können, dass Endbenutzer damit arbeiten können, da die 'Sprache' ihrem Verständnis des Problemraums entspricht und nichts anderes enthalten ist.

0

Eine Möglichkeit zum Verwalten der Softwarekomplexität besteht darin, das Framework mithilfe einer domänenspezifischen Sprache vollständig von den gewünschten Aktionen zu trennen . 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 Entwurfstool, wie beispielsweise einem Berichtsgenerator.

Um zu funktionieren, muss eine strikte Grenze gezogen werden, welche Operationen möglich sind und wie sie verknüpft sind (Skriptsprache oder visuelles Design, wie ein Formularerstellungstool). Metadaten sind eine wichtige Methode, um die Laufzeitkonfiguration von den Codierungsdetails abzugrenzen, sodass ein System eine Vielzahl gewünschter Ergebnisse unterstützen kann. Wenn die Grenzen festgelegt und eingehalten werden (und nicht jede Anfrage nach einer Erweiterung akzeptiert 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. Man könnte fast sagen, dass alle Programmiersprachen domänenspezifische Sprachen sind. Die Idee ist also endemisch und wird übersehen, weil sie so offensichtlich ist. Sie können jedoch auch eigene Skripte oder visuelle Design-Tools erstellen, um Ihr Leben zu vereinfachen. Manchmal ist es viel einfacher, ein Problem zu verallgemeinern!


0

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

Das Ziel ist - Verwalten der Softwarekomplexität . Das Ziel ist nicht "OO-Sprache verwenden".

Das ist kein Grund, ein neues Paradigma einzuführen. Es ist etwas, das natürlich passiert ist, als die Codierung reifer wurde. Es ist sinnvoller, Code zu schreiben, in dem wir am Ende des Zuges einen Bus hinzufügen (der Zug wird anhand einer verknüpften Liste modelliert), als einen neuen Knoten am Ende der verknüpften Liste hinzuzufügen.


Codierung in Bezug auf den realen Welt Entitäten ist einfach die offensichtliche und korrekte Art und Weise zu codieren , wenn wir sind Codierung über die reale Welt Einheiten.


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 Reisebusses am Ende des Zuges. Für Menschen ist es jedoch einfacher, mit dem Zug und dem Reisebus zu arbeiten als mit verknüpften Listen und Knoten, obwohl der Zug, wenn wir eine Ebene tiefer gehen, anhand einer verknüpften Liste modelliert wird.

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 , dh Dekomposition 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 Verwaltung der Komplexität, indem sie der Realität nahe kommt.

Daher programmieren Sie Objekte ein, weil es für Sie einfacher ist, zu programmieren, und es für Sie und alle anderen schneller ist, dies zu verstehen.


0

Das Einzige, woran Sie sich erinnern sollten, ist
Folgendes : Bei OOP geht es nicht um Sprachfunktionen. Es geht darum, wie Sie Ihren Code strukturieren .

OOP ist eine Art zu denken und die Architektur Ihres Codes zu entwerfen. Sie kann in nahezu jeder Sprache durchgeführt werden. Dies schließt insbesondere die einfachen Nicht-OO-Sprachen 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 sehr objektorientiert .

Das sei gesagt, OO - Features in einer Sprache stark die Menge an Standardcode reduzieren , die Sie benötigen , schreiben die gewünschten Ergebnisse zu erzielen . Wenn Sie eine virtuelle Funktionstabelle explizit definieren und mit den entsprechenden Funktionszeigern in C füllen müssen, tun Sie in Java nichts und sind fertig. OO-Sprachen entfernen einfach alles, was cruft aktiviert, aus dem Quellcode und verbergen es hinter netten Abstraktionen auf Sprachebene (wie Klassen, Methoden, Member, Basisklassen, implizite Konstruktor- / Destruktor-Aufrufe usw.).

Also, nein, wir nicht brauchen OO - Sprachen OOP zu tun. Es ist nur so, dass OOP mit einer anständigen OO-Sprache so viel einfacher ist.


-1

Objektorientierte Programmierung ist mehr als nur Module + Kapselung. Wie Sie sagen, ist es möglich, Module + Kapselung in einer nicht objektorientierten (prozeduralen) Sprache zu verwenden. OOP beinhaltet mehr als nur das: Es beinhaltet Objekte und Methoden. Also, nein, das erfasst OOP nicht. Siehe z. B. https://en.wikipedia.org/wiki/Object-oriented_programming oder die Einführung in OOP in einem guten Lehrbuch.


Danke für die Antwort. Könnten Sie einen empfehlen?
Steakexchange

-2

Der Hauptgrund dafür ist, dass ein Programm immer komplexer wird und Sie einige Teile davon für andere Teile unsichtbar machen müssen. Andernfalls lässt die Komplexität der App und die Anzahl der Funktionen Ihr Gehirn aus Ihren Ohren tröpfeln.

Stellen wir uns ein System von 100 Klassen mit jeweils etwa 20 Operationen vor, die mit ihnen ausgeführt werden können. Das sind 2.000 Funktionen. Davon sind jedoch möglicherweise nur 500 vollständige Vorgänge wie "Speichern" und "Löschen", während 1500 interne Funktionen sind, die ein wenig Wartung ausführen oder eine nützliche Funktion haben. Erwägen;

// intentionally in a non-specific language!

setName(person, name) {
    nameParts = splitPersonName(name);
    person.firstName = nameParts[0];
    person.lastName = nameParts[1];
    person.modified = true;
}

splitPersonName(name) {
    var result = [];
    result.add(name.substring(0, name.indexOf(" ")));
    result.add(name.substring(name.indexOf(" ") + 1));
    return result;
}

So SetNameist eine Funktion , die Menschen tun sollten , um eine Person, sondern SplitPersonNameist eine Nutzenfunktion verwendet durch die Person.

Eine direkte prozedurale Programmierung macht keinen Unterschied zwischen diesen beiden Operationen. Das bedeutet, dass Ihre 2.000 Funktionen um Ihre Aufmerksamkeit konkurrieren. Wenn wir diese Funktionen jedoch als "für jeden verfügbar, der über einen Personendatensatz verfügt" und "nur als Hilfsprogrammfunktion innerhalb des Personendatensatzes verwendet" kennzeichnen könnten, haben wir jetzt 500 "für alle" -Funktionen und 15 "Hilfsprogramm". Funktionen für die Klasse, die Sie bearbeiten.

Das ist was publicund privatemach es;

public class Person {
    public void setName(...) {...}
    private string[] splitPersonName(...) { ...}
}

1
Ich bin mir nicht sicher, ob Sie meine Frage richtig verstanden haben. Ich bin mir bereits der Kapselung und des Versteckens von Daten bewusst, um die Komplexität zu verwalten. Ich denke nur, dass dies auch in prozeduralen Sprachen leicht möglich ist, indem das Programm in Module unterteilt wird, die klar definierte einfache Aufgaben ausführen, deren inneres Funktionieren in separaten geschützten Quellen spezifiziert ist. Warum also OOP, wenn wir diese Dinge in prozeduralen Sprachen tun können? Das ist meine frage
Steakexchange

2
Ich denke, meine Antwort ist, dass Sie, wenn Sie so etwas tun möchten, spezielle Werkzeuge und Sprachkonstrukte schreiben müssen, um dies zu tun (z. B. einen speziellen 'include'-Aufruf für eine include-Datei, der dies möglicherweise nicht tut an anderer Stelle aufgenommen werden). Sobald Sie diesen Weg eingeschlagen haben, haben Sie tatsächlich damit begonnen, eine objektorientierte Sprache auf Ihre eigene Weise zu implementieren. Zum Beispiel war C ++ ursprünglich ein Präprozessor, der einfaches C produzierte , und ich vermute, wenn Sie Ihr System erst einmal implementiert haben, sieht es wie C ++ auf C aus.
user62575

3
@steakexchange Beachten Sie, dass OOP zu einer Zeit entwickelt wurde, als viele prozedurale Sprachen solche Module nicht hatten. Einige würden solche Sprachen nicht einmal als prozedural bezeichnen. In der Tat gibt es nichts, was besagt, dass eine prozedurale Sprache nicht OO sein darf oder umgekehrt. Seien Sie vorsichtig mit Etiketten - sie können Sie leicht irreführen. Wenn Ihre prozedurale Sprache Module mit öffentlichen und privaten Feldern und Prozeduren unterstützt, ist das gut für Sie :) Der Hauptunterschied zwischen "traditionellem prozeduralem" und "OOP" besteht darin, dass der Anrufversand in OOP flexibler ist - im strengen OOP sogar Sie weiß nie , welchen Code du aufrufst.
Luaan

2
@steakexchange In Sprachen der ML-Familie funktionieren Module hervorragend, und in Kombination mit Lambdas erhalten Sie die gesamte Leistungsfähigkeit einer beliebigen OO-Sprache (schließlich ist eine Funktion eine Schnittstelle mit einer einzigen Methode - ist das nicht fast das, was von empfohlen wird) "Guter Code" Jungs in OO?: P). Aus verschiedenen Gründen werden sie immer noch weniger verwendet als die prozeduralen Sprachen wie C ++ oder Java, aber sie haben ihren Reiz und viele Menschen versuchen, die Menschen darüber aufzuklären, wie sie ihr Leben vereinfachen können (mit mehr oder weniger Erfolg).
Luaan

C hat effektiv diese Dinge. Es hat Module (.c-Dateien) mit Schnittstellen (.h-Dateien) und kann öffentliche (extern) und nicht öffentliche (extern) Methoden (Funktionen) haben. Sie können sogar Polymorphismus des armen Mannes mit Arrays von Funktionszeigern haben, ich sage nicht, OO ist einfach in C (oder vielleicht vernünftig), aber Kapselung ist ziemlich einfach,
Nick Keighley
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.