Was passiert in OO?

35

Ich habe OO-Programmierung studiert, hauptsächlich in C ++, C # und Java. Ich dachte, ich hätte ein gutes Verständnis dafür, was Kapselung, Vererbung und Polymorphismus angeht (und ich habe viele Fragen auf dieser Site gelesen).

Eine Sache, die hier und da auftaucht, ist das Konzept des "Message Passing". Offensichtlich wird dies bei der OO-Programmierung in den heutigen Standardsprachen nicht verwendet, sondern von Smalltalk unterstützt.

Meine Fragen sind:

  • Was ist die Weitergabe von Nachrichten? (Kann jemand ein praktisches Beispiel geben?)
  • Gibt es eine Unterstützung für dieses "Message Passing" in C ++, C # oder Java?
Tom
quelle
4
Ich habe diese Frage vor einiger Zeit auf SO beantwortet: stackoverflow.com/a/3104741/10259
Frank Shearar
1
Hast du den Wikipedia-Artikel gelesen ?
Yannis
4
Meiner bescheidenen Meinung nach würde sich Objective-C als Standardsprache qualifizieren. Mindestens so viel wie C #.
Mouviciel
Ich stimme dem zu, ich habe die "Mainstream" -Sprachen aus meiner Erfahrung
Tom
Ein Member-Funktionsaufruf ist eine Implementierung des Weitergebens einer Nachricht. Die übergebene Nachricht wird durch den Funktionsnamen identifiziert und enthält die Informationen aus den Parametern. Durch die späte Bindung kann die empfangende Klasse dieselbe Nachricht anders als andere Klassen verarbeiten. Es ist nicht das, was von den Machern von Simula beabsichtigt war, und viele Leute würden dagegen protestieren, es Message-Passing zu nennen und (aus gutem Grund) zu behaupten, dass Message-Passing eine Schlüsselsache ist, die Simula unterscheidet, aber Member-Funktionsaufrufe tun im Wesentlichen immer noch dasselbe Job.
Steve314

Antworten:

60

Was ist die Weitergabe von Nachrichten? (Kann jemand ein praktisches Beispiel geben?)

Nachrichtenübergabe bedeutet einfach, dass (auf einer sehr abstrakten Ebene) der grundlegende Mechanismus der Programmausführung Objekte sind, die sich gegenseitig Nachrichten senden. Der wichtige Punkt ist, dass der Name und die Struktur dieser Nachrichten nicht unbedingt im Quellcode festgelegt sind und selbst zusätzliche Informationen sein können. Dies ist ein wichtiger Teil dessen, was Alan Kay ursprünglich als "objektorientierte Programmierung" vorstellte.

Gibt es eine Unterstützung für dieses "Message Passing" in C ++, C # oder Java?

Diese Sprachen implementieren eine eingeschränkte Version von Nachrichten, die über Methodenaufrufe weitergeleitet werden. Eingeschränkt, da die Menge der Nachrichten, die gesendet werden können, auf die in einer Klasse deklarierten Methoden beschränkt ist. Der Vorteil dieses Ansatzes besteht darin, dass er sehr effizient implementiert werden kann und eine sehr detaillierte statische Codeanalyse ermöglicht (was zu allen nützlichen Vorteilen führt, z. B. zur Vervollständigung des Codes).

Umgekehrt verfügen Sprachen, die die "echte" Nachrichtenübergabe implementieren, häufig auch über Methodendefinitionen, um Nachrichtenhandler zu implementieren. Klassen können jedoch flexiblere Nachrichtenhandler implementieren, mit denen das Objekt "Methodenaufrufe" mit beliebigen Namen empfangen kann (nicht festgelegt) zur Kompilierzeit).

Ein Beispiel in Groovy , das die Kraft dieses Konzepts demonstriert:

def xml = new MarkupBuilder(writer)
xml.records() {
  car(name:'HSV Maloo', make:'Holden', year:2006) {
    country('Australia')
    record(type:'speed', 'Production Pickup Truck with speed of 271kph')
  }
}

wird dieses XML erzeugen:

<records>
  <car name='HSV Maloo' make='Holden' year='2006'>
    <country>Australia</country>
    <record type='speed'>Production Pickup Truck with speed of 271kph</record>
  </car>
</records>

Beachten Sie, dass records, car, countryund recordsind syntaktisch Methodenaufrufe, aber es gibt keine Methoden dieses Namens definiert in MarkupBuilder. Stattdessen verfügt es über einen catchall-Meldungshandler, der alle Meldungen akzeptiert und die Meldungsnamen als Namen eines XML-Elements, Parameter als Attribute und Abschlüsse als untergeordnete Elemente interpretiert.

Michael Borgwardt
quelle
+1 direkt zur Punktantwort. Akzeptiert für das Codebeispiel. Vielen Dank für Ihre Hilfe :)
Tom
Könnte es also nicht einfach mit einer einfachen sendMessage(property_name, Array of arguments)und getMessage(property_name, Array of arguments)in statischen Sprachen implementiert werden?
Pacerier
1
@Pacerier: Sicher, aber das kombiniert die Nachteile beider Ansätze - Sie verlieren die Typensicherheit und haben immer noch "sendMessage", das Ihren Code überall verschmutzt, sodass Sie nicht die elegante Syntax erhalten.
Michael Borgwardt
Wäre es richtiger zu sagen, dass der Nachrichtenhandler im Groovy-Beispiel eine Nachricht empfängt und nicht einen Methodenaufruf? Sie setzen den Ausdruck "Methodenaufruf" anfangs in Anführungszeichen, aber in Ihrem letzten Satz sagen Sie, dass er "alle Methoden akzeptiert " und nicht "Nachrichten".
Adam Zerner
@AdamZerner: Du hast recht, ich habe es behoben.
Michael Borgwardt
28

Die Nachrichtenübergabe ist eine andere Methode, um das Erfordernis im OO-Code zu handhaben, dass ein Objekt ein anderes Objekt (oder möglicherweise sich selbst) veranlasst, etwas zu tun.

In den meisten modernen Sprachen, die vom C ++ - Ansatz abstammen, machen wir das mit Methodenaufrufen. In diesem Fall gibt das aufgerufene Objekt (über seine Klassendefinition) eine große Liste der von ihm akzeptierten Methodenaufrufe an, und der Codierer des aufrufenden Objekts schreibt einfach den Aufruf:

public void doSomething ( String input )
...
other_object.dosomething ( local )

Bei statisch typisierten Sprachen kann der Compiler dann den Typ des aufgerufenen Objekts überprüfen und bestätigen, dass die Methode deklariert wurde. Bei dynamisch getippten Sprachen erfolgt dies zur Laufzeit.

Im Wesentlichen passiert jedoch, dass ein Bündel von Variablen an einen bestimmten Codeblock gesendet wird.

Nachrichtenübergabe

In Message-Passing-Sprachen (wie Objective C) gibt es anstelle von Methoden Empfänger, aber der Ansatz, sie zu definieren und aufzurufen, ist im Großen und Ganzen derselbe - der Unterschied liegt in der Art und Weise, wie sie behandelt werden.

In einer Message-Passed-Sprache darf der Compiler überprüft , ob der von Ihnen angerufene Empfänger vorhanden ist. Im schlimmsten Fall wird jedoch eine Warnung , die besagt, dass er nicht sicher ist, ob er vorhanden ist. Dies liegt daran, dass zur Laufzeit ein Codeblock auf dem empfangenden Objekt aufgerufen wird, der sowohl das Variablenbündel als auch die Signatur des Empfängers übergibt, den Sie aufrufen möchten. Dieser Codeblock sucht dann nach dem Empfänger und ruft ihn auf. Wenn der Empfänger jedoch nicht existiert, gibt der Code einfach einen Standardwert zurück.

Infolgedessen besteht eine der Besonderheiten beim Wechsel von C ++ / Java -> Objective C darin, dass Sie eine Methode für ein Objekt "aufrufen" können, das nicht für den Typ "Kompilierungszeit" deklariert wurde und auf dem es nicht einmal vorhanden war der Laufzeit-Typ ... und dass der Aufruf nicht dazu führen würde, dass eine Ausnahme ausgelöst wird, sondern dass tatsächlich ein Ergebnis zurückgegeben wird.

Der Vorteil dieses Ansatzes besteht darin, dass die Unterklassenhierarchie geglättet wird und die meisten Anforderungen an Schnittstellen / Mehrfachvererbung / Ententypen vermieden werden. Außerdem können Objekte das Standardverhalten definieren, wenn sie aufgefordert werden, etwas zu tun, für das sie keinen Empfänger haben (normalerweise "wenn ich es nicht tue, leite die Anfrage an dieses andere Objekt weiter"). Es kann auch die Verknüpfung mit Rückrufen (z. B. für Benutzeroberflächenelemente und zeitgesteuerte Ereignisse) vereinfachen, insbesondere über statisch typisierte Sprachen wie Java (Sie können also den Empfänger mit der Schaltfläche "runTest" aufrufen, anstatt die "actionPerformed" -Methode für die innere Klasse aufzurufen) "RunTestButtonListener", der den Aufruf für Sie erledigt).

Es scheint jedoch auf Kosten der Notwendigkeit einer zusätzlichen Überprüfung durch den Entwickler zu gehen, dass der Aufruf, den er zu tätigen glaubt, sich auf dem richtigen Objekt mit dem richtigen Typ befindet und die richtigen Parameter in der richtigen Reihenfolge übergibt, da der Compiler dies möglicherweise nicht tut warnen Sie und es wird perfekt zur Laufzeit ausgeführt (nur eine Standardantwort zurückgeben). Die zusätzliche Suche und das Übergeben von Parametern sorgen für einen Performance-Hit.

Heutzutage können dynamisch typisierte Sprachen viele Vorteile von Message Passed OO mit weniger Problemen bieten.

Gavin H
quelle
1
Diese Antwort gefällt mir - erklärt die Unterschiede und ihre Auswirkungen.
HappyCat
@Gavin, Ist es also genau das gleiche wie der dynamische Methoden-Handler von PHP und Javascript ?
Pacerier
11

Nachrichtenübermittlungsarchitekturen sind einfach Systeme, bei denen jede Komponente von den anderen unabhängig ist und ein gemeinsamer Mechanismus für die Datenübermittlung zwischen ihnen besteht. Sie können Methodenaufrufe als eine Form der Nachrichtenübergabe betrachten, dies ist jedoch nicht praktikabel - es verwirrt das Problem. Dies liegt daran, dass, wenn Sie eine Klasse mit genau definierten Methoden und einen Code haben, der diese Methoden aufruft, das Ganze zusammen kompiliert werden muss, wodurch der Code und das Objekt gekoppelt werden. Sie können sehen, wie nahe es ist (während eine Nachricht übergeben wird und der Compiler die Richtigkeit erzwingt, aber ein Großteil der Flexibilität eines entkoppelten Systems verliert).

Nachrichtenübergabearchitekturen ermöglichen häufig das Hinzufügen von Objekten zur Laufzeit und häufig das Umleiten von Nachrichten an ein oder mehrere Objekte. Ich kann also einen Code haben, der eine Nachricht "data x is updated" an alle Objekte sendet, die in das System geladen wurden, und jeder von ihnen kann mit diesen Informationen eine beliebige Aktion ausführen.

Ein komisches Beispiel ist das Web. HTTP ist ein Nachrichtenübergabesystem - Sie übergeben ein Befehlsverb und ein 'Datenpaket' an einen Serverprozess. (zB GET http: \ myserver \ url) Weder Ihr Browser noch der Webserver kümmern sich um die Daten, die Sie senden oder an die Sie sie senden. Der Server leitet es an den Code weiter, der ein weiteres Datenpaket packt und an Sie zurücksendet. Keine der Komponenten in diesem System weiß etwas über die Arbeit der anderen oder was sie tun, sie kennen nur das Protokoll, das für die Nachrichtenkommunikation verwendet wird.

gbjbaanb
quelle
@ Gbjbannb, brauchen einige Pseudo-Code-Erklärungen ....
Pacerier