Как точно “Объекты общаются друг с другом путем передачи сообщений”?

В нескольких вводных текстах на Объектно-ориентированном программировании я столкнулся с вышеупомянутым оператором.

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

Что точно оператор означает в коде?

class A
{ 
    methodA()
    {

    }
}


class B
{
    methodB()
    {

    }
}


class C
{
    main()
    {
        A a=new A();
        B b=new B();
        a.methodA(); // does this mean msgs passing??
        b.methodB(); // or does this?? I may be completely off-track here..
    }
}
24
задан tjons 4 January 2017 в 14:05
поделиться

9 ответов

Если мы говорим об ООП, то термин «передача сообщений» взят из Smalltalk . Вкратце основные принципы Smalltalk следующие:

  1. Объект - это базовая единица объектно-ориентированной системы.
  2. Объекты имеют собственное состояние .
  3. Объекты общаются, отправляя и получая сообщения .

Если вас интересует Smalltalk, посмотрите Pharo или Squeak .

Java / C # / C ++ и многие другие языки используют несколько иной подход, вероятно, унаследованный от Simula . Вы вызываете метод вместо передачи сообщения.

Я думаю, что эти термины более или менее эквивалентны. Возможно, единственное интересное отличие состоит в том, что передача сообщений (по крайней мере, в Smalltalk) всегда зависит от динамической отправки и позднего связывания, тогда как в случае вызова метода можно также использовать статическую отправку и раннее связывание. Например, C ++ (AFAIK) по умолчанию выполняет раннее связывание до тех пор, пока где-то не появится ключевое слово virtual ...

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

Smalltalk прямо запрещает доступ к переменным экземпляра на уровне синтаксиса. Как я уже упоминал выше, объекты в программе Smalltalk могут взаимодействовать только путем передачи / получения сообщений.Многие другие языки разрешают доступ к переменным экземпляра на уровне синтаксиса, но это считается плохой практикой. Например, известная книга Эффективный C ++ содержит соответствующую рекомендацию: Правило 22: Объявите элементы данных закрытыми.

Причины:

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

Последний - самый важный. В этом суть инкапсуляции - сокрытие информации на уровне класса.

Дело об инкапсуляции более важно, чем может показаться на первый взгляд. Если вы скрываете элементы данных от клиентов (т. Е. Инкапсулируете их), вы можете гарантировать, что инварианты классов всегда поддерживаются, потому что только функции-члены могут влиять на них. Кроме того, вы оставляете за собой право изменить свое решение о реализации позже. Если вы не скрываете такие решения, вы скоро обнаружите, что даже если вы владеете исходным кодом класса, ваша способность изменять что-либо публичное чрезвычайно ограничена, потому что слишком много клиентского кода будет сломано. Public означает неинкапсулированный, и практически говоря, неинкапсулированный означает неизменный, особенно для широко используемых классов.Тем не менее, широко используемые классы больше всего нуждаются в инкапсуляции, потому что именно они могут получить наибольшую выгоду от возможности замены одной реализации на лучшую.

(с) Скотт Мейерс, Эффективный C ++: 55 конкретных способов улучшения ваших программ и дизайнов (3-е издание)

24
ответ дан 28 November 2019 в 22:48
поделиться

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

Что касается вызовов функций-членов, которые действительно соответствуют этим требованиям, трудно сказать с точки зрения языковой независимости. Например, в Java функции-члены по умолчанию являются виртуальными, поэтому ваши вызовы a.methodA () и b.methodB () будут эквивалентны передаче сообщения. Ваши (пытается a) вызовы b.methodA () и a.methodB () не компилируются, потому что Java статически типизирована.

Напротив, в C ++ функции-члены не виртуальные по умолчанию, поэтому ни один из ваших вызовов не эквивалентен передаче сообщений. Чтобы получить что-то эквивалентное, вам нужно явно объявить по крайней мере одну из функций-членов как виртуальную:

class A { 
    virtual void methodA() {}
};

Однако в нынешнем виде это, по сути, «различие без различия». Чтобы понять, что это означает, вам нужно использовать наследование:

struct base { 
    void methodA() { std::cout << "base::methodA\n"; }
    virtual void methodB() { std::cout << "base::methodB\n"; }
};

struct derived { 
    void methodA() { std::cout << "derived::methodA\n"; }
    virtual void methodB() { std::cout << "derived::methodB"; }
};

int main() { 
    base1 *b1 = new base;
    base2 *b2 = new derived;

    b1->methodA();   // "base::methodA"
    b1->methodB();   // "base::methodB"
    b2->methodA();   // "base::methodA"
    b2->methodB();   // "derived::methodB"
    return 0;
}
4
ответ дан 28 November 2019 в 22:48
поделиться

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

Клиентский объект не может напрямую управлять состоянием принимающего объекта. Это преимущество инкапсуляции - принимающий объект может независимо применять свое состояние и изменять свою реализацию, не влияя на то, как клиенты взаимодействуют с ним.

7
ответ дан 28 November 2019 в 22:48
поделиться

То, что вы опубликовали, не будет компилироваться ни на одном языке oop, поскольку methodB не принадлежит объекту A и methodA не принадлежит объекту B .

Если вы вызвали правильный метод, то оба они являются передачей сообщения объектом C :

a.methodA();
b.methodB();

Из википедии:

Процесс, посредством которого объект отправляет данные другому объекту или запрашивает другой объект для вызова метода.

1
ответ дан 28 November 2019 в 22:48
поделиться

Ваш пример не будет работать с Java или Python, поэтому я исправил и аннотировал ваш main

class C{
  main()
  {
   A a=new A();
   B b=new B();
   a.methodA(); // C says to a that methodA should be executed
   // C says to b that methodB should be executed
   // and b says to C that the result is answer
   answer = b.methodB(); 
  }
}
1
ответ дан 28 November 2019 в 22:48
поделиться

Не совсем ответ на ваш вопрос, но небольшое отступление о отправке сообщений и вызове метода :

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

Термин сообщение также ближе к реальности динамического языка, где вы могли бы фактически отправить сообщение, которое объект не понимает (см. doesNotUnderstand в Smalltalk). Тогда вы можете не говорить о вызове метода, учитывая, что совпадений нет, и отправка сообщения завершится ошибкой. В языке со статической типизацией эта проблема устранена.

10
ответ дан 28 November 2019 в 22:48
поделиться

Некоторые из ранних академических работ по ОО были связаны с передачей объектами сообщений друг другу для вызова поведения. Некоторые ранние языки ОО были написаны именно так (SmallTalk?).

Современные языки, такие как C++, C# и Java, вообще не работают таким образом. В них код просто вызывает методы на объектах. Это в точности похоже на процедурный язык, за исключением того, что в вызове передается скрытая ссылка на вызываемый класс ("this").

1
ответ дан 28 November 2019 в 22:48
поделиться

"Передача сообщения" - это абстракция.

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

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

В заключение: не путайте абстракции с кодом. В былые времена программистов очень заботила теория, потому что программирование едва ли существовало как основная профессия. Сегодня большинство программистов редко знакомы с теорией, стоящей за кодом. :-)

Кстати, для склонных к теории, агент-ориентированные подходы к моделированию и программированию часто подчеркивают передачу сообщений как механизм коммуникации между агентами, утверждая, что это вытекает из теории речевых актов. Здесь не происходит вызова метода.

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

9
ответ дан 28 November 2019 в 22:48
поделиться

Этот код работает?

Как бы то ни было, вы в стороне ...

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

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

0
ответ дан 28 November 2019 в 22:48
поделиться
Другие вопросы по тегам:

Похожие вопросы: