Пример. Описание предметной области.
Имеется единственная кнопка управления, доступная для пользователя печи. Если дверца печи закрыта и пользователь нажмет кнопку, печь будет готовить пищу, при этом силовой элемент будет находиться под напряжением в течение одной минуты. Если пользователь нажмет кнопку во время работы печи, то время ее работы увеличиться на одну минуту. Нажатие кнопки при открытой двери не имеет никакого эффекта. Внутри печи имеется электрическая лампочка. Во время работы печи она должна быть включена, чтобы можно было посмотреть через стекло дверцы печи и увидеть, например, что блюдо сгорело. Всякий раз, когда дверца открыта, электрическая лампочка должна гореть для того, чтобы пользователь мог видеть пищу или вымыть печь. Таким образом, лампочка горит либо при открытой двери, либо при закрытой двери и включенном силовом элементе. Если пользователь закрывает дверь, электрическая лампочка гаснет. Это нормально, если блюдо поместили в печь, но еще не нажали на кнопку. Пользователь может приостановить процесс приготовления пищи открыванием дверцы. В этом случае время сбрасывается. Если время истекло, то выключается как силовой элемент, так и лампочка. Тогда подается звуковой сигнал, сообщающий, что пища готова.
В реальных вариантах заданий на курсовое проектирование приводятся параметры законов распределения возникновения некоторых событий, а также требуется собрать статистику работы системы в течение некоторого времени. Исходные данные могут быть, как заданы числовыми константами и жестко прописаны в программном коде, так и быть неопределенными до момента запуска программы, в таком случае необходима организация ввода из консоли или файла. Для полноты описания добавим вышеприведенный пример некоторым дополнением.
1. Промежутки времени между двумя последовательными воздействиями пользователя на печь распределены нормально с математическим ожиданием 60 секунд и дисперсией 30 секунд. 2. Пользователь с одинаковой вероятностью может, как нажать на кнопку, так и открыть, или закрыть дверь. 3. Необходимо провести моделирование работы системы в течение 10 минут и собрать следующую статистику: ‒ общее время работы силового элемента печи; ‒ количество приготовленных блюд; ‒ количество прерываний приготовления блюд. 4. На каждом шаге моделирования необходимо выводить состояние системы и происходящие события. Собранную статистику необходимо вывести на экран и в файл. 5.1 Объектно-ориентированный анализ Объектно-ориентированный анализ системы можно провести двумя традиционными методами: методом Аббота и CRC-карточек, а также методом построения диаграмм вариантов использования. Use-Case Diagrams. Диаграммы вариантов использования являются действенным методом анализа, относящимся к методологии UML. Варианты использования – это описание последовательности действий, которые может осуществлять система в ответ на внешние воздействия [3]. Диаграмма вариантов использования состоит из актеров, для которых система производит действие и собственно действия Use Case, которое описывает то, что актер хочет получить от системы. Актер обозначается значком человечка, а Use Case – овалом. Дополнительно в диаграммы могут быть добавлены комментарии. Между актерами и вариантами использования могут быть различные виды взаимодействия. Основные виды взаимодействия следующие. 1. Простая ассоциация – отражается линией между актером и вариантом использования (без стрелки). Отражает связь актера и варианта использования. 2. Направленная ассоциация – то же что и простая ассоциация, но показывает, что вариант использования инициализируется актером. Обозначается стрелкой.
3. Наследование – показывает, что потомок наследует атрибуты и поведение своего прямого предка. Может применяться как для актеров, так для вариантов использования. 4. Расширение (extend) – показывает, что вариант использования расширяет базовую последовательность действий и вставляет собственную последовательность. При этом в отличие от типа отношений "включение" расширенная последовательность может осуществляться в зависимости от определенных условий. 5. Включение – показывает, что вариант использования включается в базовую последовательность и выполняется всегда. Пример. Построение диаграммы вариантов использования. На рис. 5.1 показана диаграмма вариантов использования для вышеописанной ПрО. Системой на данной диаграмме изображена микроволновая печь, а актером – человек, ее пользователь. Пользователь использует четыре варианта использования (направленная ассоциация): «Включить печь», «Выключить печь», «Приготовление пищи», «Вымыть печь». Варианты «Открыть дверь» и «Закрыть дверь» включаются в варианты «Вымыть печь» и «Приготовление пищи», кроме того в последний включаются также «Поставить блюдо», «Нажать кнопку» и «Забрать блюдо». Варианты использования, инициированные самой печью, расширяют варианты использования доступные актеру. Стоит отметить, что в системах имитационного моделирования, пользователя чаще всего имитирует некий объект, соответственно актер становится частью системы или граница системы распространяется на актера, что равнозначно. Метод Аббота. Метод Аббота заключается в словесном анализе предметной области и получении ее словаря и объектно-ориентированного словаря. Согласно этому методу надо описать задачу на обычном языке, а потом подчеркнуть существительные и глаголы [1]. Существительные – кандидаты на роль классов, а глаголы могут стать именами методов. Подход Аббота полезен, так как он прост и заставляет разработчика заниматься словарем предметной области. Однако он весьма приблизителен и непригоден для сколько-нибудь сложных проблем. Человеческий язык - ужасно неточное средство выражения, потому список объектов и операций зависит от умения разработчика записывать свои мысли.
Пример. ОО анализ предметной области методом Аббота. Таблица 5.0.1 – Словарь предметной области
При переходе от словаря ПрО (табл. 5.1) к ОО словарю (табл. 5.2) некоторые классы, свойства и методы можно ввести в независимости от наличия соответствующих существительных и глаголов. Так в нижеприведенной таблице выделен базовый класс электроприбора ElectricalAppliance, бытового прибора HouseholdAppliance и класс генератора случайных чисел Random.
Таблица 5.0.2 – ОО словарь предметной области
Продолжение таблицы 5.0.3
Обратите внимание на приведенное в скобках англоязычное название классов, свойств и методов. Так как данное пособие предусматривает программирование на языке C++, который не допускает применение других национальных алфавитов, то рекомендуется уже на этапе анализа переходить к англоязычной терминологии. Следует отметить и применяемую нотацию именования. Имена классов состоят из английских терминов, начинающихся с прописной буквы и написанных слитно без пробелов, например, PowerElement, а не Power_Element и не Power_element, и не powerElement. Имена методов формируются аналогично. Имена свойств начинаются не с прописной, а с обычной буквы, так как свойства – это переменные некоего типа, например, timeToAction, а не TimeToAction. Более подробно о правилах и нотациях именования можно прочесть в соответствующей литературе [12]. Класс генератора случайных чисел Random был введен из-за желания выделить код (ответственность) из класса Man для получения времени до следующего действия timeToAction в методе Imitate. Хотя из описания ПрО и следует, что генерация случайных чисел требуется только в одном участке программы, но разработчик всегда должен думать о ее дальнейшем развитии. Так если бы потребовалось ввести класс блюд и для некоторых из них требовалось неопределенное время приготовления, то код генерации случайных чисел дублировался бы в программе, что значительно усложнило бы ее отладку, развитие и поддержку. Обратите внимание на выделение базового класса электроприбора ElectricalAppliance. В самом начале анализа он не был бы выделен, так как в описании ПрО и соответственно в словаре ПрО о нем ничего не сказано. Но о необходимости его выделения стало бы известно при анализе с помощью следующего метода анализа. Класс бытового прибора HouseholdAppliance введен для того, чтобы показать о возможностях множественного наследования в C++, что будет показано далее. Кроме того, если в дальнейшем понадобиться ввести, например, класс электрической плиты, то в HouseholdAppliance можно будет выделить то общее, что объединяет электроплиту и микроволновую печь (например, силовой элемент). CRC-карточки. CRC обозначает Class-Responsibilities-Collaborators (Класс/Ответственности/Участники). Это эффективный способ анализа сценариев. Карты CRC впервые предложили Бек и Каннингхэм для обучения объектно-ориентированному программированию [2].
Карта представляет собой таблицу с заголовком и двумя столбцами. На карточках разработчик пишет сверху – название класса, базового или суперкласса, производных классов, снизу в левой половине – за что он отвечает, а в правой половине – с кем он сотрудничает. Проходя по сценарию, разработчик заводит по карточке на каждый обнаруженный класс и дописывает в нее новые пункты. При этом каждый раз анализируется, что из этого получается, и "выделяется излишек ответственности" в новый класс или переносятся ответственности с одного большого класса на несколько более детальных классов, или, возможно, передается часть обязанностей другому классу. Т.е. это вполне нормальная ситуация, когда разработчику необходимо переделывать ОО словарь и CRC-карты несколько раз, что говорит о важности этапа анализа. Карточки можно раскладывать так, чтобы представить формы сотрудничества объектов. С точки зрения динамики сценария, их расположение может показать поток сообщений между объектами, с точки зрения статики они представляют иерархии классов. В таблицах 5.3-5.13 приведены примеры окончательных CRC-карт, полученных после нескольких проходов по сценарию работы ПрО. Пример. ОО анализ предметной области методом CRC-карточек. Таблица 5.0.4 – CRC-карточка класса Man
Таблица 5.0.5 – CRC-карточка класса Random
Таблица 5.0.6 – CRC-карточка класса ElectricalAppliance
Таблица 5.0.7 – CRC-карточка класса Button
Таблица 5.0.8 – CRC-карточка класса Speaker
Таблица 5.0.9 – CRC-карточка класса PowerElement
Таблица 5.0.10 – CRC-карточка класса Lamp
Таблица 5.0.11 – CRC-карточка класса Timer
Таблица 5.0.12 – CRC-карточка класса HouseholdAppliance
Таблица 5.0.13 – CRC-карточка класса Door
Таблица 5.0.14 – CRC-карточка класса MicrowaveOven
Если бы мы только начинали проектирование, то в ОО словаре, вероятно, не было бы класса электроприбора ElectricalAppliance, но классы Button, Speaker, PowerElement, Lamp имели бы общие свойства и методы. А при проходе по сценарию из описания ПрО, мы бы выделили часть ответственности в этот базовый класс. В пояснительной записке студенту необходимо привести диаграмму вариантов использования и окончательные варианты словаря ПрО, ОО словаря и CRC-карт с подробными комментариями, отвечающими на следующие вопросы. 1. Какие классы и объекты предлагается ввести, чему они соответствуют в моделируемой предметной области? 2. Что является "состоянием" для объектов этих классов, набором каких параметров оно задается? 3. Какие сообщения должны принимать и обрабатывать объекты? 4. Какие информационные зависимости существуют между классами, какими общими функциями они пользуются? 5.2 Объектно-ориентированное проектирование Результатами объектно-ориентированного проектирования являются диаграммы, выполненные в нотациях Booch или UML. В нотации Booch к фазе проектирования относятся – диаграммы классов, объектов, состояний и переходов, взаимодействия [2]; а в нотации UML – диаграммы классов, объектов, последовательностей, кооперации, состояний, деятельности [3]. 5.2.1 Диаграммы классов Диаграмма классов показывает классы и их отношения, тем самым представляя логический аспект проекта и передавая структуру классов, формирующих архитектуру системы [2]. Два главных элемента диаграммы классов – это классы и их основные отношения. На рис. 5.2 показано обозначение для представления класса на диаграмме. Класс обычно представляют аморфным объектом, вроде облака, также допускается обозначение в виде прямоугольника со скругленными краями. Каждый класс должен иметь уникальное имя. На обозначениях классов полезно перечислять несколько свойств (атрибутов/полей) и методов (операций/функций-членов) класса. Атрибут обозначает часть составного объекта, или агрегата. Атрибуты используются для выражения отдельных свойств класса. В нотации Booch используется синтаксис, в котором свойство может обозначаться именем или типом данных, или и тем и другим, и, возможно, иметь значение по умолчанию: ‒ A - только имя; ‒ :C - только тип данных (класс); ‒ A:C - имя и тип данных (класс); ‒ A:C=E - имя, тип данных (класс) и значение по умолчанию. Имя свойства должно быть недвусмысленно в контексте класса. Метод – это услуга, предоставляемая классом. Методы обычно изображаются внутри значка класса только своим именем. Чтобы отличать их от свойств, к их именам добавляются скобки. Иногда полезно указать полную сигнатуру метода: ‒ N() - только имя метода; ‒ RN(Аргументы) – тип возвращаемого значения (R), имя и формальные параметры (если есть). Имена методов должны пониматься в контексте класса однозначно в соответствии с правилами перегрузки методов. Пример. Обозначение класса на диаграмме классов. На рис. 5.3 показан пример обозначения класса электроприбора ElectricalAppliance. Имена его свойств и методов взяты из ОО словаря ПрО (табл. 5.2). Свойство state имеет логический тип данных bool (включен прибор или нет) и по умолчанию установлено в значение false (выключен). Вертикальная черта слева от свойства означает, что оно имеет модификатор доступа protected, т.е. свойство защищено от доступа извне. Для доступа к свойству принято применять пару методов: для чтения – геттер GetState() и для записи – сеттер SetState(). В подобной организации логики работы со свойствами заключается принцип инкапсуляции – класс защищает свое состояние, но предоставляет открытый, контролируемый изнутри интерфейс для работы с ним. В случае класса ElectricalAppliance сеттер отсутствует, что говорит о том, что внешние сущности могут лишь наблюдать за состоянием электроприбора, но никак не могут изменить его состояние по своей воле. Вместо этого класс предоставляет свой интерфейс в виде двух методов: включение On() и выключение Off(), т.о. любая внешняя сущность может управлять состоянием электроприбора путем его включения и выключения. Причем, перед тем, как произвести воздействие на электроприбор, можно оценить его текущее состояние, иначе было бы нелогично пытаться включить уже включенный прибор или выключить выключенный. Метод Imitate() предназначен для имитирования поведения любого класса объектов в данный момент времени. Его наличие обусловлено в большей степени использованием проектируемых классов в имитационном моделировании динамических систем и процессов. Если бы у нас во всей глобальной иерархии наследования был один суперкласс, например Object, то с очень большой вероятностью у него был бы виртуальный метод Imitate(). Два метода с названиями, идентичными названию класса, называются конструктором и деструктором: ElectricalAppliance() и ~ElectricalAppliance() соответственно. Первый вызывается при создании экземпляра класса (объекта) и предназначен для инициализации начального состояния объекта. Второй вызывается при прекращении существования экземпляра класса и предназначен для освобождения классом используемых ресурсов. Используя подобное подробное обозначение, разработчик уже на этапе проектирования может приступить к составлению протоколов некоторых классов, т.е. начать выполнять этап ОО программирования. Данная возможность выполнять параллельно разные этапы разработки ПП обеспечивается еще одним принципом ОО подхода – абстракцией. Пример. Составление чернового протокола класса. Используя ОО словарь ПрО (табл. 5.2), CRC-карточку класса (табл. 5.10) и графическое обозначение класса (рис. 5.3) на диаграмме классов составим приблизительный протокол класса электроприбора ElectricalAppliance. На данном этапе мы просто переносим имя класса, имена свойств и методов на язык С++ максимально абстрагируясь от типов данных свойств, параметров и результатов методов. По возможности сохраняя все же известные модификаторы доступа, типы данных и начальные значения. Полученный протокол класса представлен ниже.
class ElectricalAppliance // класс электроприбор { protected: // защищенные члены класса bool state; // состояние
public: // открытые члены класса ElectricalAppliance(); // конструктор по умолчанию ~ElectricalAppliance(); // деструктор bool GetState(); // геттер для состояния void On(); // включить void Off(); // выключить void Imitate(); // имитировать работу в течении еденицы времени };
Профессиональные разработчики почти никогда не выполняют данный этап, а держат подобный вид протокола у себя в голове вплоть до начала этапа ОО программирования.
Как было отмечено выше, классы состоят в отношениях между собой. Виды отношений между классами показаны на рис. 5.4: ассоциация, наследование, агрегация (has) и использование [2]. При изображении конкретной связи ей можно сопоставить текстовую метку, документирующую имя этой связи или подсказывающую ее роль. Имя связи не обязано быть глобальным, но должно быть уникально в своем контексте. Значок ассоциации соединяет два класса и означает наличие семантической связи между ними. Ассоциации часто отмечаются существительными, например Employment (место работы), описывающими природу связи. Класс может иметь ассоциацию с самим собой (так называемая рефлексивная ассоциация). Одна пара классов может иметь более одной ассоциативной связи. Возле значка ассоциации можно указать ее мощность, используя синтаксис следующих примеров: ‒ 1 - в точности одна связь; ‒ N - неограниченное число (0 или больше); ‒ 0..N - ноль или больше; ‒ 1..N - одна или больше; ‒ 0..1 - ноль или одна; ‒ 3..7 - указанный интервал; ‒ 1..3, 7 - указанный интервал или точное число. Обозначение мощности пишется у конца линии ассоциации и означает число связей между каждым экземпляром класса в начале линии с экземплярами класса в ее конце. Если мощность явно не указана, то подразумевается, что она не определена. Обозначения оставшихся трех типов связи уточняют рисунок ассоциации дополнительными пометками. Это удобно, так как в процессе разработки проекта связи имеют тенденцию уточняться. Сначала отражается семантическая связь между двумя классами, а потом, после принятия тактических решений об истинных их отношениях, эта связь уточняется как наследование, агрегация или использование. Значок наследования, представляющего отношение "общее/частное", выглядит как значок ассоциации со стрелкой, которая указывает от подкласса к суперклассу. Подкласс наследует структуру и поведение своего суперкласса. Класс может иметь один (одиночное наследование), или несколько (множественное наследование) суперклассов. Как правило, циклы в наследовании запрещаются. К наследованию значок мощности не приписывается. Пример. Обозначение на диаграмме и реализация на языке C++ отношения наследования. На рис. 5.5 показан фрагмент иерархии наследования в ПрО «Микроволновая печь». Обратите внимание на изменившееся обозначения класса ElectricalAppliance. Треугольник с буквой «А» обозначает, что класс является абстрактным, т.е. невозможно создание его экземпляров. Кроме того метод Imitate() объявлен как virtual Imitate() = 0, т.е. является чисто виртуальной функцией, а значит, все дочерние классы от ElectricalAppliance обязаны реализовывать (перегружать) данный метод. Эта возможность обеспечивается принципом полиморфизма. На рисунке классы Button и MicrowaveOven наследуют класс ElectricalAppliance, что в принципе логично – и кнопка и микроволновая печь являются электроприборами. Значит, они наследуют состояние и поведение своего базового класса, т.е. их тоже можно включать, выключать, проверять их состояние. В этом и состоит принцип наследования. Так как обозначение класса ElectricalAppliance на рис. 5.5 модифицировано по сравнению с рис. 5.3, то и протокол класса будет изменен.
class ElectricalAppliance abstract // класс электроприбор - абстрактный класс { protected: // защищенные члены класса bool state; // состояние
public: // открытые члены класса ElectricalAppliance(); // конструктор по умолчанию ~ElectricalAppliance(); // деструктор bool GetState(); // геттер для состояния void On(); // включить void Off(); // выключить virtual void Imitate() = 0; // имитировать работу в течении еденицы времени // чисто виртуальная функция };
Протокол класса Button будет выглядеть следующим образом. Через двоеточие после имени класса указывается суперкласс с модификатором наследования, который определяет область видимости членов суперкласса из дочернего класса и через объект дочернего класса. Также в обязательном порядке переопределен метод Imitate().
class Button: // класс кнопка public ElectricalAppliance // наследует электроприбор { public: Button(); ~Button(); void Push(); // нажать void Imitate(); // перегруженный метод имитации работы };
Значок агрегации обозначает отношение "целое/часть" (связь "has") и получается из значка ассоциации добавлением закрашенного кружка на конце, обозначающем агрегат. Экземпляры класса на другом конце стрелки будут в каком-то смысле частями экземпляров класса-агрегата. Разрешается рефлексивная и циклическая агрегация. Агрегация не требует обязательного физического включения части в целое. Пример. Обозначение на диаграмме и реализация на языке C++ отношения агрегации. На рис. 5.6 показан пример обозначения отношения агрегации между двумя классами MicrowaveOven и Button. При этом MicrowaveOven является агрегатом по отношению к Button, и у MicrowaveOven может быть единственный экземпляр Button, а отдельный Button может принадлежать единственному MicrowaveOven. Протокол класса MicrowaveOven будет выглядеть следующим образом. В качестве одного из открытых свойств объявлен экземпляр типа Button.
class MicrowaveOven: // класс микроволновая печь public ElectricalAppliance // наследует электроприбор { public: // открытые члены класса Button button; // кнопка MicrowaveOven(); ~MicrowaveOven(); void Imitate(); // имитировать работу в течении еденицы времени };
На рис. 5.6 на конце агрегации, обозначающем часть агрегата, добавлен квадрат. Квадрат отвечает за физическое включение частей в агрегат: закрашенный – агрегация по значению, незакрашенный – агрегация по ссылке. В примере используется агрегация по значению, и поэтому в протоколе класса MicrowaveOven жестко определен объект Button. Если бы использовалась агрегация по ссылке, то был бы определен указатель на Button. Применение агрегации по значению целесообразно, когда часть постоянно принадлежит агрегату, а по ссылке – когда в процессе выполнения программы необходимо осуществлять замену частей агрегата.
class MicrowaveOven: // класс микроволновая печь public ElectricalAppliance // наследует электроприбор { public: // открытые члены класса Button* button; // указатель на кнопку MicrowaveOven(); ~MicrowaveOven(); void Imitate(); // имитировать работу в течении еденицы времени };
Знак использования обозначает отношение "клиент/сервер" и изображается как ассоциация с пустым кружком на конце, соответствующем клиенту. Эта связь означает, что клиент нуждается в услугах сервера, то есть методы класса-клиента вызывают методы класса-сервера или имеют сигнатуру, в которой возвращаемое значение или аргументы принадлежат классу сервера. Пример. Обозначение на диаграмме и реализация на языке C++ отношения использования. На рис. 5.7 показан пример обозначения отношения использования между классами Man и MicrowaveOven, Button. Класс человека Man использует класс печи MicrowaveOven для приготовления блюд, что отражено в сигнатуре метода Imitate(MicrovavrOven&). А где-то в реализации этого метода человек взаимодействует с открытым свойством печи – кнопкой Button, вызывая у нее метод нажать Push(). Протокол класса будет выглядеть следующим образом.
class Man // класс человек { protected: // защищенные члены класса int timeToAction; // время до взаимодействия с печью public: // открытые члены класса Man(); // конструктор ~Man(); // детсруктор void Imitate(// имитировать деятельность в течении еденицы времени MicrowaveOven&); // используется печь };
Пример. Диаграмма классов. На рис. 5.8 приведена диаграмма классов. На диаграмме показаны все классы, полученные на этапе ОО анализа и представленные в ОО словаре ПрО. Человек Man взаимодействует с печью MicrowaveOven через ее открытые свойства – дверь door (может открывать open() и закрывать close()) и кнопку button (может нажимать push()). Для генерации случайных чисел человек Man использует статический класс Random, обозначенный облаком с тенью. Random предоставляет интерфейс для генерации случайных чисел распределенных по равномерному закону Uniform() с указанием левой min и правой max границы отрезка и нормальному закону Normal() с указанием математического ожидания M и дисперсии D. Рисунок 5.8 – Диаграмма классов Печь MicrowaveOven наследует два базовых абстрактных класса: электроприбор ElectricalAppliance и бытовой прибор HouseholdAppliance. Печь состоит из двери door, кнопки button, спикера speaker, силового элемента powerElement, лампы lamp и таймера timer. На обозначении отношений агрегации защищенных частей печи MicrowaveOven дополнительно нанесена черта, обозначающая защищенность данной части агрегата. 5.2.2 Диаграммы объектов Диаграмма объектов показывает существующие объекты и их связи в логическом проекте системы [2]. Диаграмма представляет собой мгновенный снимок потока событий в некоторой конфигурации объектов. При анализе диаграммы объектов используются для показа семантики основных и второстепенных сценариев, которые отслеживают поведение системы. При проектировании диаграммы объектов используются для иллюстрации семантики механизмов в логическом проектировании системы. Существенные элементы диаграммы объектов – объекты и их отношения. На рис. 5.9 показан значок, который изображает объект на диаграмме объектов. Имя объекта следует синтаксису для атрибутов, и может быть записано в одной из трех следующих форм: ‒ A - только имя объекта; ‒ :C - только класс объектов; ‒ A:C - имя объекта и класса. Если несколько значков объектов на одной диаграмме используют одно и то же неквалифицированное имя (то есть имя без указания класса), то они означают один и тот же объект. В противном случае каждый значок означает отдельный объект. (На одной диаграмме могут присутствовать значки объектов с одинаковыми неквалифицированными именами, но относящиеся к разным классам, в том случае, если эти классы имеют общего предшественника. Это позволяет представить распространение операций от подкласса к суперклассу и наоборот). Если на разных диаграммах есть объекты с одинаковыми неквалифицированными именами, то это разные объекты, если только их имена не квалифицированы явно. Объекты взаимодействуют с другими объектами через связи, обозначение которых показано на рис. 5.10. Подобно тому, как объект является экземпляром класса, связь является экземпляром ассоциации. Связь между двумя объектами (включая утилиты классов) может существовать тогда и только тогда, когда существует ассоциация между соответствующими классами. Следовательно, существование ассоциаций между двумя классами означает существование коммуникации (то есть канала связи) между их экземплярами, по которой объекты могут посылать друг другу сообщения. Все классы неявно имеют ассоциации сами с собой и, следовательно, объект может послать сообщение сам себе. Пусть имеются объекты A и B и связь L между ними. Тогда A может вызвать любую операцию, имеющуюся в классе B и доступную A. То же верно для операций над A, вызываемых B. Объект, вызывающий операцию, называется объект-клиент, а объект, который предоставляет операцию, - объект-сервер. Обычно отправитель сообщения знает получателя, но обратное необязательно. В установившемся состоянии структуры классов и объектов системы должны быть согласованы. Если мы показываем на диаграмме операцию M на классе B, вызванную по связи L, то М должна быть объявлена в спецификации B, или в спецификациях его суперклассов. Как показано на рис. 5.10, рядом с соответствующей связью на диаграмме можно записать набор сообщений. Каждое сообщение состоит из следующих трех элементов: ‒ символ синхронизации, обозначающий направление вызова; ‒ вызов операции или извещение о событии; ‒ необязательный порядковый номер. Направление сообщения обозначается стрелкой, указывающей на объект-сервер. Этот символ означает простейшую форму передачи сообщений, семантика которой гарантирована только в присутствии единственного потока контроля. Вызов операции - наиболее общая форма сообщения. Она подчиняется ранее описанному синтаксису операций, но, в отличие от него, здесь могут быть приведены фактические параметры, подходящие к сигнатуре операции: ‒ N() - только имя операции; ‒ RN(arguments) - возвращаемое значение, имя и фактические параметры операции. Сопоставление фактических параметров с формальными осуществляется в порядке следования. Если возвращаемый операцией объект или фактические параметры используют неквалифицированные имена, совпадающие с другими неквалифицированными именами на диаграмме, то подразумевается, что они именуют одинаковые объекты, а следовательно, их классы должны подходить к сигнатуре операции. Таким образом, можно представлять взаимодействия, в ходе которых объекты передаются в качестве параметров или возвращаются, как результат операции. Сообщение может извещать о событии. Оно может представлять символьное имя, объект или имя некоторой операции. Во всяком случае, имя события должно быть определено на соответствующей классу объекта-сервера диаграмме переходов и состояний. Если извещение о событии является операцией, то оно может включать фактические параметры. Если порядковый номер явно не указан, то сообщение может быть послано независимо от других сообщений, указанных на данной диаграмме объектов. Чтобы указать явный порядок событий, нужно их пронумеровать. Нумерация начинается с единицы и добавляется как необязательный префикс к вызову операции или извещению о событии. Порядковый номер показывает относительный порядок посылки сообщений. Сообщения с одинаковыми номерами не
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|