Виды отношений между классами

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

Всего существует четыре основных вида отношений между классами:

q ассоциация (фиксирует структурные отношения — связи между экземплярами классов);

q зависимость (отображает влияние одного класса на другой класс);

q обобщение-специализация («is а»-отношение);

q целое-часть («part of»-отношение).

Для покрытия основных отношений большинство объектно-ориентированных языков программирования поддерживает следующие отношения:

1) ассоциация;

2) наследование;

3) агрегация;

4) зависимость;

5) конкретизация;

6) метакласс;

7) реализация.

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

Наследование — наиболее популярная разновидность отношения обобщение-специализация. Альтернативой наследованию считается делегирование. При делегировании объекты делегируют свое поведение родственным объектам. При этом классы становятся не нужны.

Агрегация обеспечивает отношения целое-часть, объявляемые для экземпляров классов.

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

Конкретизация выражает другую разновидность отношения обобщение-специализация. Применяется в таких языках, как Ada 95, C++, Эйфель.

Отношения метаклассов поддерживаются в языках SmallTalk и CLOS. Метакласс — это класс классов, понятие, позволяющее обращаться с классами как с объектами.

Реализация определяет отношение, при котором класс-приемник обеспечивает свою собственную реализацию интерфейса другого класса-источника. Иными словами, здесь идет речь о наследовании интерфейса. Семантически реализация — это «скрещивание» отношений зависимости и обобщения-специализации.

Ассоциации классов

Ассоциация обозначает семантическое соединение классов.

Пример:в системе обслуживания читателей имеются две ключевые абстракции — Книга и Библиотека. Класс Книга играет роль элемента, хранимого в библиотеке. Класс Библиотека играет роль хранилища для книг.

Виды отношений между классами - student2.ru

Рис. 9.10. Ассоциация

Отношение ассоциации между классами изображено на рис. 9.10. Очевидно, что ассоциация предполагает двухсторонние отношения:

q для данного экземпляра Книги выделяется экземпляр Библиотеки, обеспечивающий ее хранение;

q для данного экземпляра Библиотеки выделяются все хранимые Книги.

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

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

Ассоциация один-ко-многим, введенная в примере, означает, что для каждого экземпляра класса Библиотека есть 0 или более экземпляров класса Книга, а для каждого экземпляра класса Книга есть один экземпляр Библиотеки. Эту множественность обозначает мощность ассоциации. Мощность ассоциации бывает одного из трех типов:

q один-к-одному;

q один-ко-многим;

q многие-ко-многим.

Примеры ассоциаций с различными типами мощности приведены на рис. 9.11, они имеют следующий смысл:

q у европейской жены один муж, а у европейского мужа одна жена;

q у восточной жены один муж, а у восточного мужа сколько угодно жен;

q у заказа один клиент, а у клиента сколько угодно заказов;

q человек может посещать сколько угодно зданий, а в здании может находиться сколько угодно людей.

Виды отношений между классами - student2.ru

Рис. 9.11.Ассоциации с различными типами мощности

Наследование

Наследование — это отношение, при котором один класс разделяет структуру и поведение, определенные в одном другом (простое наследование) или во многих других (множественное наследование) классах.

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

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

with ...;...

use ...; ...

Package Класс_ПараметрыПолета is

type ПараметрыПолета is tagged private;

function Инициировать return ПараметрыПолета;

procedure Записывать (the: in out ПараметрыПолета);

function ТекущВремя (the: ПараметрыПолета)

return БортовоеВремя;

private

type ПараметрыПолета is tagged record

Имя: integer;

ОтметкаВремени: БортовоеВремя;

end record;

end Класс_ПараметрыПолета;

Запись параметров кабины самолета может обеспечиваться следующим классом:

with Класс_ПараметрыПолета; ...

use Класс_ПараметрыПолета; ...

Package Класс_Кабина is

type Кабина is new ПараметрыПолета with private;

function Инициировать (Д:Давление; К:Кислород;

Т:Температура) return Кабина;

procedure Записывать (the: in out Кабина);

function ПерепадДавления (the: Кабина) return Давление;

private

type Кабина is new ПараметрыПолета

with record

параметр1: Давление;

параметр2: Кислород;

параметр3: Температура

end record;

end Класс_Кабина;

Этот класс наследует структуру и поведение класса ПараметрыПолета, но наращивает его структуру (вводит три новых элемента данных), переопределяет его поведение (процедура Записывать) и дополняет его поведение (функция ПерепадДавления).

Иерархическая структура классов системы для записи параметров полета, находящихся в отношении наследования, показана на рис. 9.12.

Виды отношений между классами - student2.ru

Рис. 9.12.Иерархия простого наследования

Здесь ПараметрыПолета — базовый (корневой) суперкласс, подклассами которого являются Экипаж, ПараметрыДвижения, Приборы, Кабина. В свою очередь, класс ПараметрыДвижения является суперклассом для его подклассов Координаты, Скорость, Ориентация.

Полиморфизм

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

Рассмотрим различные реализации процедуры Записывать. Для класса ПараметрыПолета реализация имеет вид

procedure Записывать (the: in out ПараметрыПолета) is

begin

-- записывать имя параметра

-- записывать отметку времени

end Записывать;

В классе Кабина предусмотрена другая реализация процедуры:

procedure Записывать (the: in out Кабина) is

begin

Записывать (ПараметрыПолета (the)); -- вызов метода

-- суперкласса

-- записывать значение давления

-- записывать процентное содержание кислорода

-- записывать значение температуры

end Записывать;

Предположим, что мы имеем по экземпляру каждого из этих двух классов:

Вполете: ПараметрыПолета:= Инициировать;

Вкабине: Кабина:= Инициировать (768. 21. 20);

Предположим также, что имеется свободная процедура:

procedure СохранятьНовДанные (d: in out

ПараметрыПолета'class; t: БортовоеВремя) is

begin

if ТекущВремя(d) >= t then

Записывать (d): -- диспетчирование с помощью тега

end if;

end СохранятьНовДанные;

Что случится при выполнении следующих операторов?

q СохранятьНовДанные (Вполете, БортовоеВремя (60));

q СохранятьНовДанные (Вкабине, БортовоеВремя (120));

Каждый из операторов вызывает операцию Записывать нужного класса. В первом случае диспетчеризация приведет к операции Записывать из класса ПараметрыПолета. Во втором случае будет выполняться операция из класса Кабина. Как видим, в свободной процедуре переменная d может обозначать объекты разных классов, значит, здесь записан вызов полиморфной операции.

Агрегация

Отношения агрегации между классами аналогичны отношениям агрегации между объектами.

Повторим пример с описанием класса КонтроллерУгла:

with Класс_ГрафикРазворота. Класс_РегуляторУгла;

use Класс_ГрафикРазворота, Класс_РегуляторУгла;

Package Класс_КонтроллерУгла is

type укз_наГрафик is access all ГрафикРазворота;

type Контроллеругла is tagged private:

procedure Обрабатывать (the: in out Контроллеругла;

yr: укз_наГрафик);

function Запланировано (the: КонтроллерУгла;

уr: укз_наГрафик) return Секунда;

private

type КонтроллерУгла is tagged record

регулятор: РегуляторУгла;

end Класс_КонтроллерУгла;

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

Графическая иллюстрация отношения агрегации по величине (композиции) представлена на рис. 9.13.

Виды отношений между классами - student2.ru

Рис. 9.13.Отношение агрегации по величине (композиция)

Возможен косвенный тип агрегации — включением по ссылке. Если мы запишем в приватной части класса КонтроллерУгла:

private

type укз_наРегуляторУгла is access all РегуляторУгла;

type КонтроллерУгла is tagged record

регулятор: укз_наРегуляторУгла;

end Класс_КонтроллерУгла;

то регулятор как часть контроллера будет доступен косвенно.

Теперь сцепление объектов уменьшено. Экземпляры каждого класса создаются и уничтожаются независимо.

Еще два примера агрегации по ссылке и по величине (композиции) приведены на рис. 9.14. Здесь показаны класс-агрегат Дом и класс-агрегат Окно, причем указаны роли и множественность частей агрегата (соответствующие пометки имеют линии отношений).

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

роль : имяКласса.

Виды отношений между классами - student2.ru

Рис. 9.14.Агрегация классов

Виды отношений между классами - student2.ru

Рис. 9.15.Формы представления композиции

Эта роль соответствует той роли, которую играет часть в неявном (в этой нотации) отношении композиции между частью и целым (агрегатом).

Отметим, что, как представлено в правой части рис. 9.15, в сущности, свойства (атрибуты) класса находятся в отношении композиции между всем классом и его элементами-свойствами. Тем не менее в общем случае свойства должны иметь примитивные значения (числа, строки, даты), а не ссылаться на другие классы, так как в «атрибутной» нотации не видны другие отношения классов-частей. Кроме того, свойства классов не могут находиться в совместном использовании несколькими классами.

Зависимость

Зависимость — это отношение, которое показывает, что изменение в одном классе (независимом) может влиять на другой класс (зависимый), который использует его. Графически зависимость изображается как пунктирная стрелка, направленная на класс, от которого зависят. С помощью зависимости уточняют, какая абстракция является клиентом, а какая — поставщиком определенной услуги. Пунктирная стрелка зависимости направлена от клиента к поставщику.

Наиболее часто зависимости показывают, что один класс использует другой класс как аргумент в сигнатуре своей операции. В предыдущем примере (на языке Ada 95) класс ГрафикРазворота появляется как аргумент в методах Обрабатывать и Запланировано класса КонтроллерУгла. Поэтому, как показано на рис. 9.16, КонтроллерУгла зависит от класса ГрафикРазворота.

Виды отношений между классами - student2.ru

Рис. 9.16.Отношение зависимости

Конкретизация

Г. Буч определяет конкретизацию как процесс наполнения шаблона (родового или параметризованного класса). Целью является получение класса, от которого возможно создание экземпляров [22].

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

В разных языках программирования родовые классы оформляются по-разному. Воспользуемся возможностями языка Ada 95, в котором впервые была реализована идея настройки-параметризации. Здесь формальные родовые параметры записываются между словом generic и заголовком пакета, размещающего класс.

Пример:представим родовой (параметризированный) класс Очередь:

generic

type Элемент is private;

package Класс_Очередь is

type Очередь is limited tagged private;

procedure Добавить (В_0чередь: in out Очередь;

элт: Элемент );

private

end Класс_0чередь;

У этого класса один формальный родовой параметр — тип Элемент. Вместо этого параметра можно подставить почти любой тип данных.

Произведем настройку, то есть объявим два конкретизированных класса — Оче-редьЦелыхЭлементов и ОчередьЛилипутов:

package Класс_ОчередьЦелыхЭлементов is new Класс_0чередь

(Элемент => Integer);

package Класс_ОчередьЛилипутов is new Класс_0чередь

(Элемент => Лилипут);

В первом случае мы настраивали класс на конкретный тип Integer (фактический родовой параметр), во втором случае — на конкретный тип Лилипут.

Классы ОчередьЦелыхЭлементов и ОчередьЛилипутов можно использовать как обычные классы. Они содержат все средства родового класса, но только эти средства настроены на использование конкретного типа, заданного при конкретизации.

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

Виды отношений между классами - student2.ru

Рис. 9.17.Отношения конкретизации родового класса

Контрольные вопросы

1. В чем отличие алгоритмической декомпозиции от объектно-ориентированной декомпозиции сложной системы?

2. В чем особенность объектно-ориентированного абстрагирования?

3. В чем особенность объектно-ориентированной инкапсуляции?

4. Каковы средства обеспечения объектно-ориентированной модульности?

5. Каковы особенности объектно-ориентированной иерархии? Какие разновидности этой иерархии вы знаете?

6. Дайте общую характеристику объектов.

7. Что такое состояние объекта?

8. Что такое поведение объекта?

9. Какие виды операций вы знаете?

10. Что такое протокол объекта?

11. Что такое обязанности объекта?

12. Чем отличаются активные объекты от пассивных объектов?

13. Что такое роли объектов?

14. Чем отличается объект от класса?

15. Охарактеризуйте связи между объектами.

16. Охарактеризуйте роли объектов в связях.

17. Какие формы видимости между объектами вы знаете?

18. Охарактеризуйте отношение агрегации между объектами. Какие разновидности агрегации вы знаете?

19. Дайте общую характеристику класса.

20. Поясните внутреннее и внешнее представление класса.

21. Какие вы знаете секции в интерфейсной части класса?

22. Какие виды отношений между классами вы знаете?

23. Поясните ассоциации между классами.

24. Поясните наследование классов.

25. Поясните понятие полиморфизма.

26. Поясните отношения агрегации между классами.

27. Объясните нетрадиционные формы представления агрегации.

28. Поясните отношения зависимости между классами.

29. Поясните отношение конкретизации между классами.

Наши рекомендации