J'ai étudié la programmation OO, principalement en C ++, C # et Java. Je pensais que je comprenais bien l’encapsulation, l’héritage et le polymorphisme (ainsi que la lecture de nombreuses questions sur ce site).
Une chose semble apparaître ici et il y a le concept de "transmission de message". Apparemment, c'est quelque chose qui n'est pas utilisé pendant la programmation OO dans les langages traditionnels d'aujourd'hui, mais supporté par Smalltalk.
Mes questions sont:
- Qu'est-ce qu'un message qui passe? (Quelqu'un peut-il donner un exemple concret?)
- Existe-t-il une prise en charge de ce "transfert de message" en C ++, C # ou Java?
Réponses:
La transmission de messages signifie simplement que (à un niveau très abstrait) le mécanisme fondamental de l'exécution d'un programme est constitué par les objets qui s'envoient des messages. Le point important est que le nom et la structure de ces messages ne sont pas nécessairement fixés au préalable dans le code source et peuvent être eux-mêmes des informations supplémentaires. C'est une partie importante de ce que Alan Kay avait initialement envisagé comme "programmation orientée objet".
Ces langages implémentent une version limitée du message passant par les appels de méthodes. Limité car l'ensemble des messages pouvant être envoyés est limité aux méthodes déclarées dans une classe. L’avantage de cette approche est qu’elle peut être mise en œuvre de manière très efficace et qu’elle permet une analyse de code statique très détaillée (ce qui offre toutes sortes d’avantages utiles, tels que l’achèvement de code).
Inversement, les langages qui implémentent la "vraie" transmission de messages ont souvent aussi des définitions de méthodes, ce qui est un moyen pratique d'implémenter des gestionnaires de messages, mais permet aux classes d'implémenter des gestionnaires de messages plus souples permettant à l'objet de recevoir des "appels de méthodes" avec des noms arbitraires (non corrigés). au moment de la compilation).
Un exemple dans Groovy qui démontre la puissance de ce concept:
va produire ce XML:
Notez que
records
,car
,country
etrecord
sont syntaxiquement appels de méthode, mais il n'y a pas de méthodes de ce nom défini dansMarkupBuilder
. Au lieu de cela, il dispose d'un gestionnaire de messages catchall qui accepte tous les messages et interprète les noms de message comme le nom d'un élément XML, les paramètres comme attributs et les fermetures comme éléments enfants.la source
sendMessage(property_name, Array of arguments)
etgetMessage(property_name, Array of arguments)
statique?La transmission de message est une manière différente de gérer le besoin en code OO pour un objet d'obtenir un autre objet (ou potentiellement lui-même) pour faire quelque chose.
Dans la plupart des langages modernes issus de l'approche C ++, nous le faisons avec des appels de méthodes. Dans ce cas, l'objet appelé (via sa définition de classe) met une grande liste des méthodes qu'il accepte, puis le codeur de l'objet appelant écrit simplement l'appel:
Pour les langages à typage statique, le compilateur peut alors vérifier le type de la chose appelée et confirmer que la méthode a été déclarée. Pour les langages à typage dynamique, cette opération est effectuée au moment de l'exécution.
Mais ce qui se passe essentiellement, c’est qu’un ensemble de variables est envoyé à un bloc de code spécifique.
Message en passant
Dans les langues de transmission de messages (telles que Objective C) au lieu de méthodes, il y a des destinataires, mais dans l’ensemble, l’approche consistant à les définir et à les appeler est sensiblement la même - la différence réside dans la manière dont elle est traitée.
Dans une langue de message passé, le compilateur peut vérifier que le destinataire que vous avez appelé existe, mais au pire, un avertissement apparaît pour vous avertir qu'il n'est pas sûr qu'il soit là. En effet, au moment de l'exécution, un bloc de code sur l'objet récepteur sera appelé en passant à la fois le groupe de variables et la signature du destinataire que vous souhaitez appeler. Ce bloc de code recherche alors le destinataire et l’appelle. Cependant, si le destinataire n'existe pas, le code renverra simplement une valeur par défaut.
En conséquence, l’une des bizarreries trouvées lors du passage de C ++ / Java -> Objective C comprend que vous pouvez "appeler une méthode" sur un objet qui n’a pas été déclaré dans le type de compilation et n’existait même pas le le type d'exécution ... et que l'appel ne se traduirait pas par une exception mais par un résultat renvoyé.
Les avantages de cette approche sont qu’elle aplatit la hiérarchie des sous-classes et évite la plupart des besoins en interfaces / héritage multiple / types de canard. Cela permet également aux objets de définir le comportement par défaut quand on leur demande de faire quelque chose pour laquelle ils n'ont pas de récepteur (généralement "si je ne le fais pas, transférez la demande à cet autre objet"). Il peut également simplifier la liaison aux rappels (par exemple, pour les éléments d'interface utilisateur et les événements programmés), en particulier avec des langages statiques tels que Java (le bouton appelle alors le destinataire "runTest" plutôt que la méthode "actionPerformed" de la classe interne). "RunTestButtonListener" qui effectue l'appel pour vous).
Cependant, il semblerait que le développeur ait besoin de vérifier que l'appel qu'il pense est en train de passer sur le bon objet avec le bon type et de transmettre les bons paramètres dans le bon ordre, car le compilateur pourrait ne pas le faire. vous avertir et il fonctionnera parfaitement au moment de l'exécution (en renvoyant une réponse par défaut). On peut également affirmer que les performances supplémentaires résultent de la recherche supplémentaire et du dépassement des paramètres.
De nos jours, les langages à typage dynamique peuvent donner beaucoup d'avantages du message passé à OO avec moins de problèmes.
la source
Les architectures de transmission de messages sont simplement des systèmes dans lesquels chaque composant est indépendant des autres, avec un mécanisme commun pour la transmission de données entre eux. Vous pouvez considérer les appels de méthode comme une forme de transmission de message, mais ce n'est pas pratique, cela confond le problème. En effet, si vous avez une classe avec des méthodes bien définies et un code appelant ces méthodes, le tout doit être compilé ensemble, couplant ainsi le code et l'objet. vous pouvez voir à quel point il est proche (lorsqu'un message est transmis et que le compilateur applique la correction, mais il perd une grande partie de la flexibilité d'un système découplé).
Les architectures de transmission de messages permettent souvent d'ajouter des objets au moment de l'exécution et, le plus souvent, de rediriger les messages vers un ou plusieurs objets. Ainsi, je peux avoir du code qui diffuse un message "data x is updated" à tous les objets chargés dans le système, et chacun d'entre eux peut prendre les mesures qu'il souhaite avec ces informations.
Le Web est un exemple étrange. HTTP est un système de transmission de messages - vous passez un verbe de commande et un "paquet de données" à un processus serveur. (par exemple, GET http: \ myserver \ url) Ni votre navigateur, ni le serveur Web ne se soucient de quoi que ce soit des données que vous envoyez ou de l'endroit où vous les envoyez. Le serveur le transmettra au code qui emballera un autre "paquet" de données et vous le renverra. Aucun des composants de ce système ne sait quoi que ce soit du travail des autres ou de ce qu'ils font, ils connaissent simplement le protocole utilisé pour la communication du message.
la source