что такое передача сообщений в ОО?

35

Я изучал ОО-программирование, прежде всего на C ++, C # и Java. Я думал, что хорошо разбираюсь в этом с моим пониманием инкапсуляции, наследования и полиморфизма (а также прочитав много вопросов на этом сайте).

Одна вещь, которая, кажется, всплывает здесь и там, это понятие «передача сообщений». По-видимому, это то, что не используется при ОО-программировании в современных основных языках, но поддерживается Smalltalk.

Мои вопросы:

  • Что такое передача сообщений? (Может кто-нибудь привести практический пример?)
  • Есть ли поддержка этой «передачи сообщений» в C ++, C # или Java?
Том
источник
4
Я недавно ответил на этот вопрос на SO: stackoverflow.com/a/3104741/10259
Фрэнк Шеарар,
1
Вы читали статью в Википедии ?
Яннис
4
По моему скромному мнению, Objective-C будет рассматриваться как основной язык. По крайней мере, так же, как C #.
Mouviciel
Я согласен с этим, я излагал «основные» языки из своего опыта
Том
Вызов функции-члена является одной из реализаций передачи сообщения. Передаваемое сообщение идентифицируется по имени функции и включает в себя информацию из параметров. Позднее связывание позволяет получающему классу обрабатывать одно и то же сообщение другим способом. Это не то, что было задумано создателями Simula, и многие люди будут возражать против того, чтобы называть это передачей сообщений, и заявляют (по уважительной причине), что передача сообщений - это ключевая вещь, которая отличает Simula, но вызовы функций-членов по-прежнему делают то же самое. работа.
Steve314

Ответы:

60

Что такое передача сообщений? (Может кто-нибудь привести практический пример?)

Передача сообщений просто означает, что (на очень абстрактном уровне) основным механизмом выполнения программы являются объекты, отправляющие друг другу сообщения. Важным моментом является то, что имя и структура этих сообщений не обязательно заранее зафиксированы в исходном коде и могут сами по себе быть дополнительной информацией. Это важная часть того, что Алан Кей изначально представлял как «объектно-ориентированное программирование».

Есть ли поддержка этой «передачи сообщений» в C ++, C # или Java?

Эти языки реализуют ограниченную версию передачи сообщений через вызовы методов. Ограничено, потому что набор сообщений, которые могут быть отправлены, ограничен методами, объявленными в классе. Преимущество этого подхода состоит в том, что он может быть реализован очень эффективно, и он обеспечивает очень подробный статический анализ кода (который приводит ко всем видам полезных преимуществ, таких как завершение кода).

И наоборот, языки, которые обеспечивают «реальную» передачу сообщений, также часто имеют определения методов, что является удобным способом реализации обработчиков сообщений, но позволяет классам реализовывать более гибкие обработчики сообщений, которые позволяют объекту получать «вызовы методов» с произвольными именами (не исправлено). во время компиляции).

Пример в Groovy, который демонстрирует силу этой концепции:

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')
  }
}

создаст этот XML:

<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>

Следует отметить , что records, car, countryи recordсинтаксически вызовы методов, но нет методов этого имени , определенного в MarkupBuilder. Вместо этого он имеет обработчик сообщений catchall, который принимает все сообщения и интерпретирует имена сообщений как имя элемента XML, параметры как атрибуты и замыкания как дочерние элементы.

Майкл Боргвардт
источник
+1 прямо к точечному ответу. Принято для примера кода. Спасибо за вашу помощь :)
Том
Так не может ли это быть просто реализовано на простых sendMessage(property_name, Array of arguments)и getMessage(property_name, Array of arguments)статических языках?
Pacerier
1
@Pacerier: конечно, но это сочетает в себе недостатки обоих подходов - вы теряете безопасность типов и все еще имеете «sendMessage», загрязняющий ваш код везде, поэтому вы не получите элегантный синтаксис.
Майкл Боргвардт
Правильнее ли будет сказать, что в примере Groovy обработчик сообщений получает сообщение, а не вызов метода? Сначала вы помещаете кавычки вокруг фразы «вызов метода», но в последнем предложении вы говорите, что он «принимает все методы », а не «сообщения».
Адам Зернер
@AdamZerner: ты прав, я это исправил.
Майкл Боргвардт
28

Передача сообщений - это другой способ удовлетворения потребности в ОО-коде для того, чтобы один объект заставил другой объект (или, возможно, сам) что-то сделать.

В большинстве современных языков, которые происходят от подхода C ++, мы делаем это с помощью вызовов методов. В этом случае вызываемый объект (через определение класса) помещает большой список того, что вызывает метод, который он принимает, и затем кодировщик вызывающего объекта просто записывает вызов:

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

Для статически типизированных языков компилятор может затем проверить тип вызываемой вещи и подтвердить, что метод был объявлен. Для динамически типизированных языков это выполняется во время выполнения.

Но, по сути, происходит то, что пакет переменных отправляется в определенный блок кода.

Передача сообщений

В языках передачи сообщений (таких как Objective C) вместо методов есть приемники, но в целом подход определения и вызова их во многом аналогичен - различие заключается в способе его обработки.

На языке передаваемых сообщений компилятор может проверить, что получатель, который вы вызвали, существует, но в худшем случае он выдаст предупреждение о том, что он не уверен, что он там есть. Это происходит потому, что во время выполнения будет вызван блок кода на принимающем объекте, передающий как пакет переменных, так и сигнатуру получателя, которого вы хотите вызвать. Затем этот блок кода ищет получателя и вызывает его. Однако, если получатель не существует, тогда код просто вернет значение по умолчанию.

В результате одна из странностей, обнаруженных при переходе с C ++ / Java -> Objective C, заключается в понимании того, что вы можете «вызвать метод» для объекта, который не был объявлен в типе времени компиляции и даже не существует в тип времени выполнения ... и что вызов не будет вызывать исключение, а фактически будет возвращать результат.

Преимущества этого подхода состоят в том, что он выравнивает иерархию подкласса и устраняет большинство потребностей в интерфейсах / множественном наследовании / типах утки. Он также позволяет объектам определять поведение по умолчанию, когда их просят сделать что-то, для чего у них нет получателя (обычно «если я этого не делаю, перенаправьте запрос этому другому объекту»). Это также может упростить привязку к обратным вызовам (например, для элементов пользовательского интерфейса и синхронизированных событий), особенно в статически типизированных языках, таких как Java (так что вы можете заставить кнопку вызывать получатель «runTest», а не вызывать метод «actionPerformed» для внутреннего класса). "RunTestButtonListener", который делает вызов для вас).

Однако может показаться, что за счет необходимости дополнительной проверки разработчиком, что вызов, который они совершают, находится на правильном объекте с правильным типом и передачей правильных параметров в правильном порядке, потому что компилятор может не предупреждаю вас, и он будет отлично работать во время выполнения (просто возвращая ответ по умолчанию). Также возможно снижение производительности от дополнительного просмотра и передачи параметров.

В наши дни языки с динамической типизацией могут дать много преимуществ ОО, передаваемых сообщениями, с меньшим количеством проблем.

Гэвин Х
источник
1
Мне нравится этот ответ - объясняет различия и их последствия.
HappyCat
@Gavin, так это точно так же, как обработчик динамических методов PHP и Javascript ?
Pacerier
11

Архитектуры передачи сообщений - это просто системы, в которых каждый компонент независим от других, с общим механизмом передачи данных между ними. Вы можете рассматривать вызовы методов как форму передачи сообщений, но это непрактично - это запутывает проблему. Это потому, что если у вас есть класс с четко определенными методами и некоторый код, который вызывает эти методы, все это должно быть скомпилировано вместе, таким образом, связывая код и объект. Вы можете видеть, как оно близко (когда сообщение передается, и компилятор обеспечивает его корректность, но он теряет большую часть гибкости отсоединенной системы).

Архитектуры передачи сообщений часто позволяют добавлять объекты во время выполнения и чаще всего позволяют перенаправлять сообщения одному или нескольким объектам. Таким образом, у меня может быть некоторый код, который передает сообщение «данные х обновлены» всем объектам, которые были загружены в систему, и каждый из них может предпринять любое действие с этой информацией.

Странный пример - сеть. HTTP - это система передачи сообщений - вы передаете командный глагол и «пакет данных» процессу сервера. (например, GET http: \ myserver \ url) Ни ваш браузер, ни веб-сервер не заботятся ни о данных, которые вы отправляете, ни о том, куда вы их отправляете. Сервер передаст его в код, который упакует другой «пакет» данных и отправит его вам. Ни один из компонентов в этой системе ничего не знает о работе других или о том, что они делают, они просто знают протокол, используемый для передачи сообщений.

gbjbaanb
источник
@ gbjbannb, нужны пояснения псевдокода ....
Pacerier