Последний раз обновлено 27.06.01
Под парадигмой в данном случае понимается набор фундаментальных правил, которые отличают ООП от других методов программирования. Мы не будем вдаваться в тонкости, какой язык объектный, какой язык объектно-ориентированный, а где просто программирование с АТД, потому что нам, как начинающим пользователям языка, это пока все равно - все равно ничего не понятно.
Терминами, которые употребляют на С++ являются эти. Это длинно, некрасиво и не всегда понятно, когда чему что соответствует, иногда требуется еще и префикс виртуальная. Из соображений экономии, слова "виртуальная" и "члены" опускаются, когда кому вздумается, что приводит к появлению просто "данных" и "функций". Чтобы не громоздить префиксы и не путать объектное с необъектным, мы не будем использовать эти термины и определять их, по крайней мере, сейчас.
Самым лучшим способом узнать что-то новое является попытка отбросить все старое и принять новое как оно есть, а затем уже попытаться увязать новое со старым. Таким образом поступим и мы.
В мире ООП нет функций и данных, там живут объекты и только объекты. Это вроде аксиомы. Что значит объекты? Объекты - просто нечто, у которого есть имя. Если бы у него не было имени, мы бы и не знали, что оно есть. Если кто любит геометрическую интерпретацию, то можно на бумажке обозначать объекты квадратиками или кружками с именем, кто не любит – просто именем без фигур. В нашем примере с океаном это будут объекты:
рыбы, трава и океан.
Сами по себе объекты интересны, но бесполезны. Как отразить их взаимодействие? Объект может принимать сообщения. Именно с помощью сообщений, которые передаются между объектами, и происходит взаимодействие. Сообщение - просто имя, которым назван некоторый набор информации, в том числе пустой, т.к. сам факт прихода сообщения несет в себе информацию. Ни с чем более сообщение сравнить нельзя. Это тоже вроде аксиомы.
Сообщение переносит информацию в обе стороны и разную: в объект получатель и из объекта получателя. Но считается, что сообщением владеет тот объект, который его получает, обрабатывает информацию и отправляет результат обработки отправителю. Часто рассматривают односторонний перенос информации.
На бумажке сообщения можно отобразить стрелочками внутрь объекта приемника с именами, либо списком имен. Договоримся здесь обозначать сообщения ( чтоб не рисовать кружочки ) аналогично доступу к структуре в С, где вместо имени структуры будет имя объекта, а вместо поля - имя сообщения, дополненное функциональными скобками. В нашем примере это:
океан–>настал_день() , рыба–>ешь_траву() и т.д.
Программы ООП - куча объектов и сообщений между ними. Ну, вот, в общем, и все. Это основные и единственные действующие лица в программе на ООП. Очень просто запомнить.
Те действия, которые выполняет объект при получении сообщения, называют методом реализации сообщения или просто методом. Метод и сообщение не одно и тоже, как отличны тип и переменная. Сообщение можно рассматривать по этой аналогии как тип метода.
Расширим определение объекта, что не повлияет на схему программы, но поможет нам. Объекту можно приписать помимо сообщений, которые он может принимать и имени еще ряд свойств. Свойство это нечто, у чего есть имя, т.е. по сути, некоторый подобъект. Сообщения можно тоже считать свойствами, но специального назначения. Сообщения - свойства, но не все свойства - сообщения. Объекты можно рассматривать как именованный набор свойств и сообщений. Свойства условимся обозначать как сообщения, но без функциональных скобок. В нашем примере свойства объектов:
рыба–>размер, рыба–>чувство_голода и т.д.
Если в программе будут действовать несколько объектов с совершенно одинаковыми свойствами, то говорят, что они принадлежат к одному классу. Это определение, но для нас, чтобы мы могли описать объекты, так как во время выполнения программы классов не существует. Описав класс, мы описываем все возможные объекты этого класса. В контексте, где существуют классы, т.е. во время компиляции, а не выполнения, объект называют экземпляром класса, а описание класса называют протоколом класса. Класс можно считать типом объекта. В нашем примере это классы:
тихий_океан, рыбы_океанские и трава_обыкновенная.
Любой язык программирования, который претендует на поддержку технологии ООП должен допускать следующие качества объектов.
Совокупность классов полученных наследованием называют иерархией классов. Мне нравится использовать также название линия наследования - именно не разветвленная последовательность классов, полученная наследованием. Один базовый класс может дать более одной линии наследования.
Наследование это такой механизм создания свойства объекта, который позволяет объявить это свойство для разных объектов ( базового и любого производного класса ) одинаковым для шаблона, использующего это свойство, и производный объект для шаблона этим свойством не отличается от базового. Альтернативными наследованию являются механизмы вложения свойства-объекта и явного описания свойства, которые не создают равнозначность для шаблона.
Существует несколько вариантов использования полиморфизма, о которых будет говориться далее, но, чтобы подзадорить, приведу такой пример.
Пусть в нашей программе "посажено" и "произрастает" "мое_растение", т.е. есть:
Мы можем "посадить" в программе "дерево", "куст" или "траву". Все они - "растения" ( т.е. "растение" их один из базовых классов ) и могут "расти" ( принимать сообщение расти() ). Тогда можно создать такой код на неком абстрактном объектном языке:
класс растение
{
умеет:
расти()как?{неизвестно,неопределено;}=0;
};
класс трава: растение //укажем, что трава тоже растение
{
умеет:
расти()как?
{
как трава:
маленькая;
зеленая;
растет быстро;
}
};
класс куст: растение
{
умеет:
расти()как?
{
как куст:
средней высоты;
ветки с листиками, бывают ягоды;
растет со средней скоростью;
}
};
класс дерево: растение
{
умеет:
расти()как?
{
как дерево:
большой высоты;
толстый ствол, похоже на крупный куст;
растет медленно;
}
};
объявить объект: мое_растение класса: растение;
мое_растение=посадить(дерево);
мое_растение–>расти();
мое_растение=посадить(куст);
мое_растение–>расти();
мое_растение=посадить(траву);
мое_растение–>расти();
В каждом случае растение растет по-своему. Вот это и есть один из видов полиморфизма, и называется это программировать в рамках и терминах задачи, в данном случае, в терминах выращивания растений.
Именно эти слова, которые были описаны здесь, мы и будем использовать для программирования на ООП. Я умышленно не употребляю слов функция и данные ( многим наверняка хочется связать это все уже сейчас с С-моделью ) хотя бы потому, что нет такой однозначной связи. Сейчас, такая связь будет не помогать, а мешать. И еще, посмотрев на последний абзац предыдущей главы, мы все же разделим работу на две части: создание модели и ее реализацию на С/С++.
Мы не будем изучать строгие правила или разного рода обобщенные теоретические положения для объектной модели. Рассмотрим лишь частные случаи, которые, может, и не всегда работают, но ограничимся этим, что для начала позволит для большого числа случаев создавать объектную модель.
Для описания модели нужны определения, правила и условные обозначения. Для С-модели мы говорили, что ее можно создавать в виде текстовых предложений, а можно прямо, хотя это и хуже, операторами языка с комментариями, СП язык для этого и разрабатывался.
Обычно, все советуют начать составление модели с создания классов С++. Я считаю, что по ряду причин, синтаксис С++ годится вполне для описания, но никак не для создания и работы с объектной моделью. Дело в том, что класс С++ не просто описывает объект, он еще и явно указывает механизм связи между объектами и своими свойствами, который может быть неизвестен на этапе создании объекта.
Не всякую абстракцию стоит выделять как класс С++. Затруднительны и преобразования с объектами при разработке модели, если объекты описаны как класс С++. Класс С++ описывает готовый объект для компилятора. Можно так же считать, что класс С++ описывает не сообщения, а методы их реализации.
Поэтому, помимо введенных, надо ввести еще новые термины и обозначения для создания и работы с моделью. В начале мы сделаем такую структуру объектов, которая будет успешно функционировать в неком виртуальном пространстве, а затем модернизируем ее для описания на С++.
Все слышали об иерархии классов. Я же предлагаю еще использовать иерархию сообщений. Что это и что это дает: совокупность всех сообщений для всех объектов образует иерархию сообщений. Именно иерархию, т.к. объект образует одноименную группу сообщений, а объекты можно наследовать или вкладывать один в другой, т.е. к сообщению можно обратиться указав все группы в которые оно входит, что выглядит как иерархия, например: редактор_текста->редактировать->\
вставить_в_позицию_курсора(введенный_с_клавиатуры_символ);
Использование иерархии сообщений позволяет говорить о пространстве сообщений, которое отражает объектную модель с точки зрения передачи информации между объектами. В пространстве сообщений живут сообщения, или информационные потоки и объекты, или узлы этих потоков.
Передача информации задает основные действия программы. Свойства объектов, те которые явно не используются для передачи информации, в пространстве сообщений рассматриваются как комментарии.
Использование пространства сообщений позволяет создать каркас модели и образовать основные объекты без детализации их определений и реализаций, позволяет сначала описывать только целевые сообщения, т.е. те сообщения, которые совершают основную работу программы, затем добавлять еще и вспомогательные сообщения, обслуживающие целевые.
Таким образом, использование пространства сообщений позволяет создавать модель, на этапе создания постепенно детализируя свойства, причем частично описанный объект там вполне жизнеспособен.
Пространство сообщений должно позволить нам отложить явное указание механизма создания объекта, но можно указать механизм на правах комментария.
Часть сообщений для объекта можно произвольным образом объединять в группы, чтобы ограничить логическое применение этих сообщений. Наличие группы выглядит как свойство, для которого определены эти сообщения, т.е. как отдельный полноценный объект. В пространстве сообщений, свойства объектов, те которые не влияют на передачу информации, рассматриваются как комментарии, а те которые влияют, могут рассматриваться просто как логическая группа сообщений.
Наличие группы свойств не означает обязательно механизм вложенности какого-либо объекта класса С++, это может быть наследование, прямое описание, локальный класс либо namespace
в новых версиях С++.
Таким образом, все объекты пространства сообщений состоят из сообщений ( контекст имен по умолчанию ) и групп сообщений ( свойств ).
Предлагаемое пространство сообщений значительно упрощено по сравнению с полной О-моделью. В нем использование объекта не разделяется на объявление, определение и создание. Пространство сообщений довольно статично, оно просто показывает распределение информации в программе. Мы можем ссылаться на объект по его имени как на группу сообщений и не обязаны детализировать его устройство, описание объекта (класс) необязательно.
Поэтому мы не будем в контексте пространства сообщений упоминать класс, чтобы оставить это имя для класса С++, класса описания О-модели, который может не совпасть с объектами пространства сообщений и не уточнять все время про какое пространство идет речь. Упрощение достигнуто за счет того, что мы отложили определение механизма создания объекта.
Использование пространства сообщений должно облегчить переход от реальной задачи к модели. Часто реальная задача задана очень расплывчато или расплывчато ее решение. У Страуструпа можно прочитать следующее "... В идеальном случае подход к разработке программы делится на три части: вначале получить ясное понимание задачи, потом выделить ключевые идеи, входящие в ее решение, и, наконец, выразить решение в виде программы. Однако подробности задачи и идеи решения часто становятся ясны только в результате попытки выразить их в виде программы - именно в этом случае имеет значение выбор языка программирования…" Очень правильное замечание. Не только подробности реализации, но даже и сам ход процесса при начале работы бывает совершенно неясен: либо из-за множества вариантов, либо из-за сложности алгоритмизации. Но что-то мы знать должны о программе, которую пишем, хотя бы ее основное назначение.
В случае неразрешимых проблем, придется сначала написать программу, реализующую первый попавшийся вариант, поработать с ней, что позволит ясно сформулировать требования и поставить задачу. Для ООП требуется четкая постановка задачи, а не получение ее в процессе программирования, что для многих программистов структурного языка кажется необычным. Работа с ООП моделью позволяет, задав основное назначение и реализовав его, затем модернизировать модель локально, без глобальных перетрясок кода.
Как начать создание О-модели? В О-модели живут объекты и сообщения, а ООП позволяет решать задачу в рамках и терминах задачи. Эти утверждения позволяют нам сказать, что начать разработку программы стоит с формирования объектов задачи. Это кажется логичным и простым. Но нужно отличать объекты контекста задачи от объектов реализации, поддержки, контекста задачи. Для выяснения разницы рассмотрим такой пример.
Свойства объектов контекста задачи определяются только условиями задачи, поэтому эти объекты будут модернизироваться при изменении условий задачи, например: вы сделали программу рассчета безопасной перевозки пассажиров на поездах, теперь вы изменили условие и занимаетесь рассчетом безопасных перевозок на самолетах. Возможность повторного использования объектов контеста задачи готового проекта сомнительна, так как непонятно, как вы приспособите стрелки, рельсы, тепловозы и стоп-краны для описания перевозок на самолетах.
Если условия задачи не изменились, то все модификации программы, при правильном составлении объектов задачи, касаются лишь изменения объектов реализации. Множно предположить, что из-за схожести задач перевозки на поездах и самолетах многие объекты реализации, что не похоже на объекты задачи, могут быть использованы и в том и в другом проекте.
Таким образом:
Если состав объектов контекста задачи достаточно определен, то объекты реализации ничем не ограничены и может существовать большое число вариантов реализаций.
Объекты и сообщения контекста задачи составляют словарь предметной области. Какие свойства решаемой задачи выделять в отдельные объекты и сообщения зависит от задачи. Главное и единственное, что должен позволять словарь предметной области, это решать типовые задачи предметной области, разумеется, в рамках предметной области. Если вы не знаете задач предметной области, значит, вы не знаете, что делает программа и не можете описать "ничего". Попробуем на примерах выделить объекты контекста задачи.
Я взял примеры, которые всем понятны, предметная область которых достаточно проста, поэтому можно сосредоточиться на свойствах ООП. Этим же объясняется выбор ОС при их реализации - dos4gw, и консольный вариант WIN32. Здесь нет проблем с памятью ( flat модель ), скорости, при которых важны побочные эффекты переключений в реальный режим, мы не используем, и хотя нет стандартных развитых средств и библиотек отображения, обычный VGA c 16 цветами и разрешением 640х480 для графики и банальный текстовый режим обеспечит все необходимое и спасет от изучения Windows всех, кто не владеет этим в совершенстве.
Главное, чтобы эти объекты позволяли решать все действия контекста задачи отправкой соответствующих сообщений. Такие разделения на объекты можно получить для большинства задач таким образом.
Далее надо детализировать сообщения объектов, которые позволят выполнять основные действия задачи. Детализация происходит так, что мы просто пытаемся решать нашими объектами типовые задачи предметной области, передавая соответствующую информацию. Как уже говорилось выше, для ООП модели требуется четкая постановка задачи, или надо реализовать любой набор требований в задаче-тесте для того, чтобы определить остальное.
Не нужно сразу, при нахождении сообщений тут же их оптимизировать или анализировать, главное, чтобы сообщения могли выполнить ту работу, которая на них возложена. Не нужно и уточнять параметры сообщений и тип результата, считая, что может передаваться любое количество параметров. Обратите внимание, что мы нигде не говорим о параметрах сообщений. Сообщение - это не функция. Важно ограничить логический тип информации и спрятать все за именем сообщения.
Объекты контекста задачи как-то взаимодействуют, и создается система сообщений. То взаимодействие, определение которого не нужно для решения задачи не может быть обнаружено без выяснения последовательности действий или еще каких то выяснений. Но эти сообщения, по счастью, не входят в контекст задачи.
Использование шаблона работы с разными объектами означает в большинстве случаев, что используется наследование. Для пространства сообщений это безразлично. На этапе создания, чтобы использовать шаблон, надо будет выбрать механизм наследования для создания объектов, общее у них выделяется в один базовый объект. Подробнее о механизмах в разделе "Реализация объектной модели"
При детализации происходит распределение свойств между объектами, формирование объектов. Для контекста задачи, логические границы объектов и свойства, в том числе и сообщения, заданы из условия задачи.
Свойства же свойств объектов контекста задачи ничем не ограничены, и представляет определенную трудность разделение их на группы и дальнейшая детализация. Какова цель логического разделения свойств, и по каким критериям его проводить? Вот некоторые из них:
В общем, при получении объектов реализации желательно, как видно из примера с поездами и самолетами, чтобы они могли использоваться в сходных по смыслу проектах, т.е. разрабатываемый проект может использовать уже готовые объекты в качестве объектов реализации, если обоснованно указать их свойства среди множества вариантов нельзя.
Рассмотрим такой пример. Пусть нам нужно в некотором объекте отобразить входные данные ряда типов ( текстовый поток, архивированный текст, рисунок ). Такой входной поток изменяемого формата можно представить как несколько независимых одноформатных входных потоков, логически разделить.
Можно создать объект-фильтр, который преобразует разные входные потоки в одинаковый выходной мета-формат, вберет в себя все детали преобразования и определит интерфейс для объекта-пользователя этого фильтра. Такой фильтр представляет собой буфер между изменяемым форматом входных данных и выходными данными. Или, что одинаково, между набором разнотипных входных потоков и однотипным выходным потоком.
Объект свяжет такой фильтр с входными данными, и для их любых известных типов будет использоваться один шаблон кода для отображения.
Объект всегда можно представить как нечто, служащее для преобразования входной информации в выходную с помощью сообщений объекта. Фактически, объекты будут представлять собой узлы, преобразующие один вид информации в другой. Такие узлы разделяют потоки информации для локального использования. Вид информации определяется группой сообщений.
Этим отличается объектная модель, которая задает схему преобразования информации, какая информация в какую, как бы стратегию преобразования, а не последовательность действий, необходимых для этого, как в структурной модели.
Последовательность действий конечно существует, но она оперирует ограниченным числом узлов-объектов и их видами информации, а не всеми видами информации программы, т.е. разбита на ограниченные, слабо связанные подсхемы, что существенно снижает сложность ее сопровождения и позволяет локально модернизировать код.
Можно еще сказать, что объектная модель не отвечает на вопрос "Что должно быть сделано?", а задает "Что дано" и "Что надо получить". Поэтому когда происходит определение сообщений и объектов контекста задачи, то они оказываются явно заданы свойствами задачи. Те сообщения и объекты, которые не нужны для решения задачи не могут быть обнаружены специалистом в данной предметной области и не войдут в словарь предметной области. Возможен не единственный вариант разделения задачи на объекты и сообщения, которые будут отличаться представлением задачи для разных специалистов предметной области.
При создании кода, последовательности действий, отображения мета-формата, мы просто используем, т.е.задаем, такие сообщения к входному потоку и другим объектам, какие нам необходимы для решения. Все отличия и преобразования имеющихся типов информации в нужный для отображения, вберут в себя объекты, к которым идет обращение. Эти объекты будут буфером, обеспечивающим локальное использование информации.
Создание кода - это фактически создание последовательности действий. Для задания этого мы можем воспользоваться методом, подобным методу для С-модели, работая вместо функций и переменных с сообщениями и свойствами. Сложность разработки такого кода существенно ниже, чем при С-модели. Как уже говорилось, вид информации ограничен рассматриваемым целевым объектом, код разбит на локальные подсхемы с понятной логикой, число рассматриваемых объектов в каждой подсхеме меньше, чем необходимо для нормальной работы структурной программы.
Чем же тогда такая объектная модель отличается от модульной структурной программы, т.е. просто от разделения задачи на модули? Отличие в механизмах реализации этого модульного разделения, т.е. в реализации самих модулей. Я затрудняюсь пока это изложить коротко и ясно. Попробуем, после ознакомления со специфическими для объектов механизмами реализации, сначала реализовать предложенную объектную модель а потом попробуем сравнить с аналогичной, но реализованной на СП. А теперь забудем про СП.
Не существует, видимо, однозначного взгляда на природу вещей. Приведу пример Буча с кошкой, в котором кошка взглядом патологоанатома ( набор органов ) и бабушки с вязанием ( пуховый шар с возможностью мурлыкать ) выглядят по разному. Главное, что бабушка не будет препарировать кота, а патологоанатом кошек держать их дома. У них действительно кошка - разный объект модели, потому что у них разные предметные области. Поэтому, когда встречаешь пример, что сладкая вата это скорее частный случай сладости, чем ваты, то он означает, что предметная область объекта - вкусовые качества, это просто неявно утверждается, но если предметная область - похожесть на что-то, то сладкая вата скорее частный случай ваты и пуха, чем конфет.
Если бы, к большому огорчению, у нас была возможность заявить, что сладкая вата либо вата, либо конфета, то это существенно снижало бы возможности повторного использования объектов и шаблонов кода. Файловые операции могут объединиться с базой данных в одном объекте. Но каждая группа может разрабатываться в своем пространстве сообщений, в котором не существует другой. Мы можем создать в программе разных котов, которые отражают либо взгляд бабушки, либо взгляд патологоанатома. А затем супер-кота, объединяющий две эти абстракции, который будет обеспечивать взаимодействие составляющих и может иметь свои новые свойства. Можно сделать так, что бабушка и патологоанатом, глядя на этого супер-кота, не смогут отличить его от кота своей предметной области. Каждую такую группу свойств мы будем называть видом на объект.
Такая группа свойств бессмысленна в контексте другой. Эти группы представляют независимые или ортогональные свойства объекта. Такая многоликость характерна для многих объектов, и для определенной предметной области возможны самые необычные связи с другими предметными областями.
Разделение сложности задачи на более простые составляющие называют декомпозицией. Заметим, что предложенная выше декомпозиция - назовем ее декомпозиция задачи - по составлению предметной области вряд ли может привести к созданию таких объектов, как отображаемый объект с универсальными свойствами и сообщениями поддержки drag&drop или универсальный список, которые потом будут использоваться в разных объектах. Сами объекты, полученные, видимо, разной декомпозицией, друг от друга принципиально не отличаются, а отличаются только лишь способами их создания. В чем же разница в подходе создания объекта из условий задачи и такого универсального объекта?
Декомпозиция задачи имеет разделяющий характер, можно сказать, ее объекты сильно независимы, она изолирует свойства для их независимой детализации. Объект же элемента отображения наоборот, предназначен для объединения принципиально разных, с точки зрения контекста задачи, объектов - дает всем объектам, которые будут его использовать, своеобразную связь, логически не обоснованную в контексте задачи, но вполне обоснованную в контексте, например, вывода на экран.
Минусы разделяющей декомпозиции - это избыточный код. Но это позволяет локально модернизировать свойства и сообщения. Вспомним, что программирование - процесс итерационный. Получаемую модель надо постепенно описывать и выявлять пути дальнейшей работы. Во время получения более-менее устойчивой схемы сообщений, нужно игнорировать оптимизацию. Исключением является случаи, когда от неоптимальной схемы сообщений невозможна нормальная работа или когда приходится явно дублировать и сопровождать несколько совершенно идентичных копий кода.
Когда получена более-менее устойчивая схема сообщений, можно не обращать внимания на задачу. Что это значит? Это значит, что можно оставить в покое ассоциативность в контексте задачи и смотреть с ортогональных задаче позиций ( что в данном случае означает "с несвязанных с" ). Это позволит выявлять общности у принципиально разных с точки зрения задачи объектов. Такие общности называют ассоциативными связями.
Для структурного подхода, такая общность часто нарушает модульность. ООП позволяет избегать прямых зависимостей, добавляет особые механизмы, как бы ограничивая глубину связи. Именно такой, ортогональный контексту задачи вид на объект, позволяет выявить и создать универсальную абстракцию типа универсального объекта для отображения, заметив, что над всеми элементами отображения совершаются одинаковые действия по их перетаскиванию.
Декомпозиция задачи разделяющая и позволяет решать задачу в терминах задачи. Затем образуются ортогональные виды, которые выделяют новые объекты и увеличивают повторное использование и уменьшают необходимость сопровождать несколько идентичных алгоритмов. Эти ортогональные виды на объект не влияют, кроме редких случаев, на внешние для модернизируемого объекта объекты. Сам этот модернизируемый объект становится как бы набором секций-видов.
Получилось, что вся сложность создания, вернее, реализации системы объектов и сообщений контекста задачи, перенесена, фактически, на образование видов на объект, т.е. на нахождение ассоциативных связей у разных объектов, и рассмотрение этих объектов в контексте этих связей, т.к. в создании абстракции по условиям задачи особых проблем возникнуть не должно. Это не похоже на методы создания АТД, которое мы использовали ранее, перенося часть операций над данными, полученных при разработке С-модели, в контекст АТД.
Я не знаю универсальных методов разрешения этих сложностей. Фактически, это уменьшенные контекстом задачи ( появился обоснованный набор объектов и сообщений ) те же проблемы, что и были при создании программы: неограниченность в поиске и вообще, нет зацепки.
Другая сложность, это выработка механизмов реализации свойств и найденных ассоциативных связей. В определенной мере, при образовании видов используется знание методов их возможной реализации и выбора наилучшего, т.к. иначе свойства можно задавать почти как угодно произвольно. Поиску механизмов и их описанию посвящена глава "Реализация на С++".
Для справки отметим, что взаимодействие нескольких объектов можно рассматривать как отношение клиент-сервер. При этом сервер предоставляет некоторый интерфейс для клиета. Интерфейс - это группа сообщений. Но часто для пользования сервером недостаточно знать просто интерфейс, посылаемые серверу сообщения могут зависеть от состояния объекта-сервера в данный момент времени. Правила использования сервера в зависимости от его состояния можно назвать протоколом взаимодействия объектов.
В отличие от пространства сообщений, которое описывает статическое состояние объектной модели, протокол взаимодействия описывает ее динамическое поведение. Протокол взаимодействия инкапсулирован в клиенте. Можно сказать, что разные клиенты, объекты-клиенты разных классов, отличаются деталями протокола, те, что не отличаются, могут считаться при данном взаимодействии идентичными объектами.
Конечно, хотелось бы, чтобы взаимодействие было как можно чаще статическим, не зависящим от состояния или чтобы протокол был инкапсулирован в сервере, а не в клиенте. Но протокол является сгруппированными в одном месте теми связями программы, которые дают программе выполняться и избавиться от них нельзя. Разумеется, один интерфейс может быть лучше другого, плохим соединением модулей можно свести на нет все преимущества модульности.