In der Alan Kays Definition von objektorientiert gibt es diese Definition, die ich teilweise nicht verstehe:
OOP bedeutet für mich nur Messaging, lokale Aufbewahrung und Schutz sowie das Verbergen von Staatsprozessen und extremes LateBinding aller Dinge.
Aber was bedeutet "LateBinding"? Wie kann ich dies auf eine Sprache wie C # anwenden? Und warum ist das so wichtig?
object-oriented
object-oriented-design
Luca Zulian
quelle
quelle
Antworten:
"Bindung" bezieht sich auf das Auflösen eines Methodennamens in einen aufrufbaren Code. Normalerweise kann der Funktionsaufruf zur Kompilierungszeit oder zur Verbindungszeit aufgelöst werden. Ein Beispiel für eine Sprache mit statischer Bindung ist C:
Hier kann der Aufruf
foo(40)
vom Compiler aufgelöst werden. Dies ermöglicht frühzeitig bestimmte Optimierungen wie Inlining. Die wichtigsten Vorteile sind:Andererseits verschieben einige Sprachen die Funktionsauflösung auf den letztmöglichen Moment. Ein Beispiel ist Python, wo wir Symbole im laufenden Betrieb neu definieren können:
Dies ist ein Beispiel für eine späte Bindung. Es macht zwar eine strenge Typprüfung unangemessen (die Typprüfung kann nur zur Laufzeit durchgeführt werden), ist jedoch weitaus flexibler und ermöglicht es uns, Konzepte auszudrücken, die nicht innerhalb der Grenzen der statischen Typisierung oder der frühen Bindung ausgedrückt werden können. Zum Beispiel können wir zur Laufzeit neue Funktionen hinzufügen.
Der in „statischen“ OOP-Sprachen üblicherweise implementierte Methodenversand liegt irgendwo zwischen diesen beiden Extremen: Eine Klasse deklariert den Typ aller unterstützten Operationen im Voraus, sodass diese statisch bekannt sind und typgeprüft werden können. Wir können dann eine einfache Nachschlagetabelle (VTable) erstellen, die auf die tatsächliche Implementierung verweist. Jedes Objekt enthält einen Zeiger auf eine vtable. Das Typsystem garantiert, dass jedes Objekt, das wir erhalten, eine geeignete vtable hat, aber wir haben zum Zeitpunkt der Kompilierung keine Ahnung, welchen Wert diese Nachschlagetabelle hat. Daher können Objekte verwendet werden, um Funktionen als Daten weiterzugeben (der halbe Grund, warum OOP und Funktionsprogrammierung gleichwertig sind). Vtables können problemlos in jeder Sprache implementiert werden, die Funktionszeiger unterstützt, z. B. C.
Diese Art der Methodensuche wird auch als "dynamischer Versand" bezeichnet und liegt irgendwo zwischen früher und später Bindung. Ich betrachte den dynamischen Methodenversand als die zentrale definierende Eigenschaft der OOP-Programmierung, wobei alles andere (z. B. Kapselung, Subtypisierung, ...) zweitrangig ist. Es ermöglicht uns, Polymorphismus in unseren Code einzuführen und einem Code sogar neues Verhalten hinzuzufügen, ohne ihn neu kompilieren zu müssen! Im C-Beispiel kann jeder eine neue vtable hinzufügen und ein Objekt mit dieser vtable an übergeben
sayHelloToMeredith()
.Während dies eine späte Bindung ist, ist dies nicht die von Kay favorisierte „extreme späte Bindung“. Anstelle des konzeptionellen Modells „Methodenversand über Funktionszeiger“ verwendet er „Methodenversand über Nachrichtenübermittlung“. Dies ist eine wichtige Unterscheidung, da das Weiterleiten von Nachrichten weitaus allgemeiner ist. In diesem Modell verfügt jedes Objekt über einen Posteingang, in den andere Objekte Nachrichten einfügen können. Das empfangende Objekt kann dann versuchen, diese Nachricht zu interpretieren. Das bekannteste OOP-System ist das WWW. Hier sind Nachrichten HTTP-Anforderungen und Server sind Objekte.
Zum Beispiel kann ich den programmers.stackexchange.se Server fragen
GET /questions/301919/
. Vergleichen Sie dies mit der Notationprogrammers.get("/questions/301919/")
. Der Server kann diese Anfrage ablehnen oder mir einen Fehler zurücksenden oder mir Ihre Frage stellen.Die Fähigkeit der Nachrichtenübergabe besteht darin, dass sie sehr gut skaliert werden kann: Es werden keine Daten gemeinsam genutzt (nur übertragen), alles kann asynchron erfolgen und Objekte können Nachrichten nach Belieben interpretieren. Dies macht ein OOP-System für die Nachrichtenübermittlung leicht erweiterbar. Ich kann Nachrichten senden, die möglicherweise nicht jeder versteht, und entweder mein erwartetes Ergebnis oder einen Fehler zurückerhalten. Das Objekt muss nicht im Voraus deklarieren, auf welche Nachrichten es antworten wird.
Dies überträgt die Verantwortung für die Aufrechterhaltung der Korrektheit auf den Empfänger einer Nachricht, ein Gedanke, der auch als Kapselung bezeichnet wird. Beispielsweise kann ich eine Datei nicht von einem HTTP-Server lesen, ohne sie über eine HTTP-Nachricht anzufordern. Dadurch kann der HTTP-Server meine Anfrage ablehnen, z. B. wenn mir Berechtigungen fehlen. In kleinerem OOP bedeutet dies, dass ich keinen Lese- / Schreibzugriff auf den internen Status eines Objekts habe, sondern öffentliche Methoden durchlaufen muss. Ein HTTP-Server muss mir auch keine Datei bereitstellen. Es könnte dynamisch generierter Inhalt aus einer Datenbank sein. In der realen OOP kann der Mechanismus, wie ein Objekt auf Nachrichten reagiert, ausgeschaltet werden, ohne dass ein Benutzer dies bemerkt. Dies ist stärker als "Reflexion", aber normalerweise ein vollständiges Metaobjektprotokoll. Mein C-Beispiel oben kann den Versandmechanismus zur Laufzeit nicht ändern.
Die Möglichkeit, den Versandmechanismus zu ändern, impliziert eine späte Bindung, da alle Nachrichten über benutzerdefinierten Code geleitet werden. Und das ist äußerst leistungsfähig: Mit einem Metaobjektprotokoll kann ich Funktionen wie Klassen, Prototypen, Vererbung, abstrakte Klassen, Schnittstellen, Merkmale, Mehrfachvererbung, Mehrfachversand, aspektorientierte Programmierung, Reflexion, Remote-Methodenaufruf, hinzufügen. Proxy-Objekte usw. in eine Sprache, die nicht mit diesen Funktionen beginnt. Diese Fähigkeit zur Weiterentwicklung fehlt in statischeren Sprachen wie C #, Java oder C ++ vollständig.
quelle
Späte Bindung bezieht sich darauf, wie Objekte miteinander kommunizieren. Das Ideal, das Alan zu erreichen versucht, besteht darin, dass Objekte so locker wie möglich gekoppelt werden. Mit anderen Worten, dass ein Objekt das Minimum kennen muss, um mit einem anderen Objekt zu kommunizieren.
Warum? Denn das fördert die Fähigkeit, Teile des Systems unabhängig voneinander zu verändern, und ermöglicht es ihm, organisch zu wachsen und sich zu verändern.
In C # können Sie beispielsweise eine Methode für
obj1
etwas wie schreibenobj2.doSomething()
. Sie können dies alsobj1
Kommunikation mit betrachtenobj2
. Damit dies in C # geschieht,obj1
muss man einiges darüber wissenobj2
. Es muss seine Klasse kennen. Es hätte überprüft, ob die Klasse eine aufgerufene Methode hatdoSomething
und ob es eine Version dieser Methode gibt, die keine Parameter akzeptiert.Stellen Sie sich nun ein System vor, auf dem Sie eine Nachricht über ein Netzwerk oder ähnliches senden. Sie könnten so etwas schreiben
Runtime.sendMsg(ipAddress, "doSomething")
. In diesem Fall müssen Sie nicht viel über die Maschine wissen, mit der Sie kommunizieren. Es kann vermutlich über IP kontaktiert werden und wird etwas tun, wenn es die Zeichenfolge "doSomething" empfängt. Aber sonst weißt du sehr wenig.Stellen Sie sich nun vor, so kommunizieren Objekte. Sie kennen eine Adresse und können beliebige Nachrichten mit einer Art "Postfach" -Funktion an diese Adresse senden. In diesem Fall
obj1
muss nicht viel darüber wissenobj2
, nur die Adresse. Es muss nicht einmal wissen, dass es verstehtdoSomething
.Das ist so ziemlich der Kern der späten Bindung. In Sprachen, die es verwenden, wie Smalltalk und ObjectiveC, gibt es normalerweise etwas syntaktischen Zucker, um die Postfachfunktion zu verbergen. Ansonsten ist die Idee dieselbe.
In C # können Sie es sozusagen replizieren, indem Sie eine
Runtime
Klasse haben, die eine Objektreferenz und eine Zeichenfolge akzeptiert und mithilfe von Reflection die Methode findet und aufruft (es wird mit Argumenten und Rückgabewerten kompliziert, aber es wäre möglich hässlich).Bearbeiten: um einige Verwirrung hinsichtlich der Bedeutung der späten Bindung zu beseitigen. In dieser Antwort beziehe ich mich auf die späte Bindung, da ich verstehe, dass Alan Kay sie gemeint und in Smalltalk implementiert hat. Es ist nicht die üblichere, modernere Verwendung des Begriffs, die sich allgemein auf den dynamischen Versand bezieht. Letzteres deckt die Verzögerung beim Auflösen der genauen Methode bis zur Laufzeit ab, erfordert jedoch zur Kompilierungszeit noch einige Typinformationen für den Empfänger.
quelle