Язык описания объектных разработок
Построение диаграмм классов
Для реализации объектов используют специальные типы – классы. Класс – это структурный тип данных, который включает описание полей данных, а также процедур и функций, работающих с этими полями данных.
Одним из наиболее значимых достоинств ООП является то, что большинство классов для реализации объектов не приходится разрабатывать «с нуля». Обычно классы строят на базе уже существующих, используя механизмы, реализующие определенное отношение существующего и строящего классов между собой: наследование, композицию, наполнение, полиморфное наследование.
Наследованием называют отношение между классами, при котором один класс строится на базе второго посредством добавления полей и определения новых методов. При этом исходный класс, на базе которого выполняется построение, называют родительским или базовым, а строящейся класс – потомком или производным классом.
При наследовании поля и методы родительского класса повторно не определяют, предусмотренный механизм наследования позволяет использовать эти компоненты класса, специально этого не оговаривая.
Отношения между различными классами проекта принято иллюстрировать диаграммой отношений классов или просто диаграммой классов. Если на диаграмме отношений классов показано только отношение наследования, то такую диаграмму называют иерархией классов.
На диаграмме классов согласно UML (см. раздел 2.3) наследование изображают линией со стрелкой, направленной к классу-родителю (см. рисунок 10).
Рисунок 10 - Примеры иерархий классов: с одним потомком (а, в) и с двумя потомками (б)
Кроме отношения между классами на диаграмме классов целесообразно бывает указать поля и методы каждого или только строящегося класса, так как это позволяет уточнить структуру разрабатываемых классов. Поля и методы перечисляют в специальных секциях уточненного обозначения класса (см. рисунок 11).
Рисунок 11 - Условное обозначение класса с указанием полей и методов
Композицией называют такое отношение между классами, когда один является частью второго. Физически, композиция реализуется включением в класс фиксированного количества полей, являющихся объектами другого класса. Такие поля обычно называют объектными.
На диаграмме классов композицию изображают линией с ромбом на конце, подходящем к более сложному классу (см. рисунок 12).
Рисунок 12 - Примеры диаграмм классов, изображающих композицию: с одним объектным полем (а) и несколькими объектными полями различных типов (б)
Наполнением называют такое отношение между классами, при котором точное количество объектов одного класса, включаемых в другой класс, не ограничено и может меняться от 0 до достаточно больших значений. Физически наполнение реализуется с использованием указателей на объекты. В отличие от объектного поля, которое включает в класс точно указанное количество объектов (1 или более – при использовании массива объектов или нескольких объектных полей) конкретного класса, использование указателей позволяет включить 0 или более объектов, если они собраны в массив или списковую (линейную или нелинейную) структуру.
На диаграмме классов наполнение изображают аналогично композиции, но ромб не закрашивают, показывая более слабую связь объектов классов (см. рисунок 13).
Рисунок 13 - Пример диаграммы классов с наполнением
Для определения отношения имеющегося и строящегося классов необходимо выполнить анализ структуры объектов предметной области, полученных в результате объектной декомпозиции.
Если объекты предметной области слишком сложны, чтобы ставить им в соответствие некий простой класс, то процесс декомпозиции можно продолжить, выделяя внутри сложных объектов более простые.
При этом возможны следующие варианты.
1. Внутри объекта можно выделить объект близкого назначения, но с более простой структурой и/или поведением – класс для реализации данного объекта следует строить на базе более простого, используя наследование. Если при этом объекты строящего класса отличаются от объектов базового класса некоторыми аспектами поведения, то следует изменить поведение объектов строящего класса при наследовании, используя полиморфное наследование с переопределение методов.
2. Внутри объекта можно выделить определенное количество объектов более простой структуры со своим поведением – класс конструируется объединением объектов других классов с добавлением полей и методов строящегося класса – композиция классов.
3. Внутри объекта можно выделить заранее не предсказуемое количество объектов более простой структуры со своим поведением – класс конструируется с возможностью динамического подключения объектов других классов (наполнение) и добавлением полей и методов строящегося класса.
Рассмотрим два примера.
Пример 6. Разработать класс для реализации объекта «Текст», который должен:
· для каждого слова некоторой последовательности слов хранить его атрибуты (тип шрифта и размер букв);
· определять количество слов в тексте;
· добавлять слова после слов с указанными номерами;
· удалять заданные слова из теста;
· менять местами слова с заданными номерами;
· заменять одно заданное слово на другое во всем тексте;
· позволять переопределять атрибуты слова с заданным номером.
Итак, реализуемый объект должен оперировать с некоторыми внутренними объектами «Словами», для которых можно определить собственное состояние и поведение. Естественно создать специальный класс TWord для реализации «Слов». Класс TText для реализации «Текста» может быть построен как с использованием композиции, так и с использованием наполнения.
В первом случае он должен включать массив объектов класса TWord. Максимальное количество элементов массива должно быть определено заранее и, следовательно, ограничено (см. рисунок 14, а). При выполнении операций удаления и вставки придется сдвигать и раздвигать элементы массива.
Во втором случае класс TText должен включать список объектов класса TWord (см. рисунок 14, б). Ограничения предыдущей реализации будут сняты, но реализация со списком имеет несколько большую трудоемкость, и, кроме того, при обращении к слову по номеру придется каждый раз последовательно отсчитывать нужный элемент. Выбор конкретного варианта реализации зависит от условий решаемой задачи.
Рисунок 14 - Диаграммы классов для реализации объекта Текст: с композицией (а) и с наполнением (б)
Пример 7. Разработать классы для реализации объектов Табулятор, Определитель корней и Определитель экстремумов из примера 3.
Объекты Табулятор, Определитель корней и Определитель экстремумов отвечают за реализацию методов решения некоторых частных задач при исследовании функций. Они имеют много общего. Попробуем определить это общее.
Любой объект, получив управление должен ввести диапазон изменения аргумента [a, b], решить подзадачу, вывести результаты, а затем вернуть управление меню операций. Общее поведение и поля объектов опишем в классе TMetod. Основной метод этого класса Run должен реализовывать общее поведение и обеспечивать возможность изменения элементов этого поведения (решения конкретных подзадач) для объектов классов, которые будут от него наследоваться. Решение конкретной подзадачи реализуем как внутренний метод Task, вызываемый из метода Run. Этот внутренний метод для класса TMetod определять не будем (абстрактный метод).
Классы для реализации разрабатываемых объектов наследуем от TMetod, переопределяя метод Task и добавляя недостающие поля (см. рисунок 15).
Рисунок 15 - Иерархия классов для реализации объектов Табулятор, Определитель корней и Определитель экстремумов
При разработке программ с использованием объектного подхода часто строят диаграммы классов, на которых показывают также отношение ассоциации, которое отражает взаимодействие объектов классов между собой в процессе работы программы. Поскольку наполнение и композиция также предполагают взаимодействие, ассоциацию используют либо на ранних этапах разработки, либо, если отношение классов не подходит под определение композиции или агрегации. Ассоциация может иметь имя, каждый элемент ассоциации может иметь имя и указание множественности (см. рисунок 16).
Рисунок 16 - Обозначение ассоциации:
а – с указанием имени ассоциации и ее направления; б – с указанием имен ролей;
в – с указанием множественности
С середины 90-х годов для документирования объектных разработок все шире применяют язык UML (Unified Modeling Language – Унифицированный Язык Моделирования). В настоящее время он фактически признан стандартным средством описания проектов, создаваемых с использованием объектно-ориентированного подхода. Создателями этого языка являются ведущие специалисты в этой области: Гради Буч, Ивар Якобсон и Джеймс Рамбо, которые использовали в своем языке все лучшее, что появилось в подходах различных авторов в предыдущие годы.
Модель проекта программного обеспечения по замыслу авторов языка может включать большое количество диаграмм различных типов, но использующих единую систему обозначений. Среди диаграмм наиболее часто используемыми являются:
· диаграммы вариантов использования или прецедентов (uses case diagrams) – показывают основные функции системы для каждого типа пользователей – применяются на этапе анализа требований и построения спецификаций;
· диаграммы классов (class diagrams): контекстные, описания интерфейсов и реализации – демонстрируют отношения классов между собой – используются соответственно на этапе анализа, этапе проектирования и этапе реализации;
· диаграммы деятельностей (activity diagrams) – представляет собой схему потоков управления для решения некоторой задачи по отдельным действиям, допускает наличие параллельных и/или альтернативных действий – применяются при анализе потоков действий одного или взаимодействующих вариантов использования;
· диаграммы взаимодействия (interaction diagrams) двух альтернативных типов:
а) диаграммы последовательности действий (sequence diagrams) – отображает упорядоченное по времени взаимодействие объектов в процессе выполнения варианта использования – применяются на стадии анализа для выявления ответственности каждого класса,
б) диаграммы кооперации (collaboration diagrams) – предоставляют ту же информацию, что и диаграммы последовательности действий, но в другой форме;
· диаграммы состояний объекта (statechart diagrams) – показывают состояния объекта и условия переходов из одного состояния в другое – используются для проектирования объектов с большим количеством состояний;
· диаграммы пакетов (package diagrams) – демонстрируют связи наборов классов, объединенных в пакеты, между собой – может использоваться вместо диаграммы классов на этапе анализа и/или физического проектирования программного обеспечения;
· диаграммы компонентов (component diagrams) – показывают, из каких программных компонентов состоит система и как эти компоненты связаны между собой;
· диаграммы размещения (deployment diagrams) – позволяет связать программные и аппаратные компоненты системы – в основном используется при проектировании распределенных программных систем.
При разработке этих диаграмм используют условные обозначения, представленные в таблицах 3 - 7.
Кроме того, спецификация может включать формализованные и неформализованные текстовые описания, комментарии и словари.
Таблица 3 - Условные обозначения вариантов использования
№ | Компонент модели | Условное обозначение | № | Компонент модели | Условное обозначение |
Действующее лицо | ![]() | Связь | ![]() | ||
Вариант использования или прецедент | ![]() | Связи «Расширение» и «Использование» | ![]() |
Таблица 4 - Условные обозначения диаграмм классов и пакетов
№ | Компонент модели | Условное обозначение | № | Компонент модели | Условное обозначение |
Класс со скрытыми секциями | ![]() | Обобщение | ![]() | ||
Класс с раскрытыми секциями | ![]() | Интерфейс | ![]() | ||
Класс (пиктограмма) | ![]() | Реализация интерфейса (раскрытая) | ![]() | ||
Граничный класс | ![]() | Реализация интерфейса классом | ![]() | ||
Управляющий класс | ![]() | Реализация интерфейса пакетом | ![]() | ||
Класс-сущность | ![]() | Использование интерфейса классом | ![]() | ||
Активный класс | ![]() | Использование интерфейса пакетом | ![]() | ||
Абстрактный класс | ![]() | Двунаправленная ассоциация | ![]() | ||
Видимость атрибутов класса | ![]() | Однонаправленная ассоциация | ![]() | ||
Абстрактная операция класса | ![]() | Агрегация | ![]() | ||
Параметризованный класс | ![]() | Композиция | ![]() | ||
Настроенный класс | ![]() | Отношение ассоциации класса | ![]() | ||
Пакет со скрытой секцией | ![]() | Зависимость классов | ![]() | ||
Пакет с раскрытой секцией | ![]() | Зависимость пакетов | ![]() | ||
Пакет (пиктограмма) | ![]() | Примечание | ![]() |
Таблица 5 - Условные обозначения диаграмм последовательностей действий
№ | Компонент модели | Условное обозначение | № | Компонент модели | Условное обозначение | |
Объект | ![]() | Возврат управления из процедуры | ![]() | |||
Вызов процедуры или вложенного потока управления | ![]() | Линия жизни | ![]() | |||
Простой поток управления | ![]() | Фокус управления | ![]() | |||
Асинхронный поток сообщений | ![]() | Разрушение объекта | ![]() |
Таблица 6 - Условные обозначения диаграмм состояний и деятельностей
№ | Компонент модели | Условное обозначение | № | Компонент модели | Условное обозначение | ||
Начало | ![]() | Переход | ![]() | ||||
Конец | ![]() | Линейки синхронизации | ![]() | ||||
Деятельность | ![]() | Состояние | ![]() | ||||
Выбор | ![]() | Составное состояние | ![]() | ||||
Таблица 7 - Условные обозначения диаграмм размещения и компоновки
№ | Компонент модели | Условное обозначение | № | Компонент модели | Условное обозначение |
Программный компонент | ![]() | База данных | ![]() | ||
Текстовый файл | ![]() | Таблица | ![]() | ||
DLL | ![]() | Узел | ![]() |