ВУЗ: Университет управления «ТИСБИ»
Категория: Учебное пособие
Дисциплина: Объектно-ориентированное программирование
Добавлен: 20.10.2018
Просмотров: 1810
Скачиваний: 9
5. Взаимодействие объектов: агрегация и композиция
Как уже было отмечено, объектная программа – это набор
взаимодействующих объектов разных классов, совместно реализующих
объектную модель. Создание программ, содержащих объекты одного-двух
классов вряд ли принесет ощутимый результат. Объектный подход – это
средство борьбы со сложностью создаваемых программных систем, в
которых используются десятки классов, связанных между собой
различными способами.
Существует несколько основных способов взаимодействия объектов,
причем отражением этих взаимодействий на формальном уровне являются
отношения между соответствующими классами. Поэтому построение
объектной модели – это выделение необходимых классов и установление
между ними определенных отношений.
Пожалуй, наиболее понятным способом взаимодействия объектов
является случай, когда один объект включает в себя в качестве
составляющих частей объекты других классов. В этом случае между
классами устанавливается отношение типа “часть-целое”. В оригинальной
англоязычной литературе такое отношение описывается термином “has-a”
(имеет, содержит, включает в себя). В теории ООП такой тип отношения
называют агрегацией. При этом различают строгую и нестрогую агрегацию.
Нестрогая агрегация – это такое взаимодействие объектов, при котором
составной объект и образующие его части могут существовать независимо
и отдельно друг от друга. Строгая агрегация или композиция возникает
тогда, когда существование составного объекта зависит от существования
входящих в него частей.
Очень важно понимать, что отношение агрегации/композиции можно
устанавливать далеко не между любыми объектами. Поэтому первое, с чего
следует начинать, это выяснение возможности установления подобной
связи.
Предположим, имеются два объекта А и B разных классов. Между ними
можно установить отношение агрегации, если утверждение «Объект A
можно рассматривать как составную часть объекта B» не противоречит
здравому смыслу.
Приведем несколько примеров из разных предметных областей.
1. Объект «Компьютер» можно рассматривать как набор более простых
объектов, таких как «Основная (материнская) плата», «Монитор»,
«Жесткий диск», «Мышь», «Клавиатура». В свою очередь, объект
«Основная плата» можно рассматривать состоящим из более простых
объектов типа «Процессор», «Основная память» и др.
2. Геометрический объект «Окружность» может включать в себя более
простой объект «Точка» для хранения координат своего центра; аналогично
объект «Прямоугольник» может состоять из двух объектов-точек, которые
задают координаты двух его противоположных углов. Более того, составной
объект «Деталь» можно разложить (декомпозировать) на отдельные
составляющие – объекты «Окружность», «Отрезок», «Прямоугольник» и
т.д.
3. Объект «Оконное приложение» содержит хотя бы один объект типа
«Оконная форма», который в свою очередь может включать такие объекты
как «Кнопка», «Поле ввода», «Список», «Таблица», «Переключатель» и
т.д.
4. Объект «Контейнер-массив динамических списков» состоит из
отдельных объектов типа «Динамический список», каждый из которых в
свою очередь состоит из объектов типа «Элемент динамического списка».
С другой стороны – контрпример: объект «Стул» вряд ли стоит
рассматривать как часть объекта «Стол» и поэтому эти объекты не следует
связывать отношением агрегации/композиции.
Необходимо отметить, что с течением времени связи между объектами
могут меняться, что является отражением изменения самой объектной
модели, вызванное изменением исходных объектов. Например, если лет 20
назад утверждение «Компьютер можно рассматривать как ЧАСТЬ
автомобиля» противоречило общепринятым понятиям, то в настоящее
время оно вполне имеет право на существование.
Следующим шагом после выяснения возможности использования
композиционной связи является разработка необходимых классов.
Очевидно, что в любой объектной информационной модели будет
существовать некоторый набор классов, которые описывают неделимые
объекты, т.е. объекты, не содержащие других объектов. Такие классы
объявляются обычным стандартным образом. А вот классы для составных
объектов имеют некоторые особенности описания.
Прежде всего, в состав свойств таких классов должны быть включены
свойства объектного типа или другими словами – переменные
соответствующих классовых типов. Поскольку такие переменные являются
неявными указателями на объекты, с их помощью можно во время
выполнения программы связывать между собой необходимые объекты.
Пример фрагмента описания составного класса ComboClass с
использованием объектных свойств классовых типов SimpleClass1 и
SimpleClass2:
class = ComboClass
subObject1 : SimpleClass1;
subObject2 : SimpleClass2;
// обычные свойства
. . . . . . . . . .
end;
ComboClass class {
SimpleClass1 subObject1;
SimpleClass2 subObject2;
// обычные свойства
. . . . . . . . . .
};
Схематично связь составного объекта с его объектами-частями можно
представить следующим образом:
свойство 1
свойство 2
составной объект
класса ComboClass
простой объект класса SimpleClass1
Наличие адресных связей между объектами предоставляет составному
объекту следующие возможности:
использовать данные, которые хранятся внутри связанных с ним
объектов (как правило – через методы доступа)
вызывать открытые методы связанных объектов, т.е. использовать
ранее созданный программный код
В целом, механизм агрегации/композиции позволяет конструировать
сложные объекты на основе ранее созданных объектов, постепенно
наращивая уровень сложности.
В качестве примера можно привести два варианта описания класса
объектов «Компьютер». В первом варианте для хранения информации о
процессоре и основной памяти используются строковые поля:
TComputer = class
cpu : string;
memory : string;
. . . . . . . . .
end;
Computer class
{ string cpu;
string memory;
. . . . . . . . . .
};
Этот вариант можно использовать в простых случаях, но когда о
процессоре и памяти надо иметь более подробную информацию,
целесообразно ввести отдельные (самостоятельные) классы для объектов
«Процессор» и «Память», а в классе «Компьютер» использовать механизм
композиционных связей с помощью полей объектного типа.
объектное свойство
subObject1
объектное свойство
subObject2
обычные свойства
. . . . . . . . . .
свойство 1
свойство 2
простой объект класса SimpleClass2
TCPU = class
// поля и методы класса «Процессор»
TMem = class
// поля и методы класса «Память»
TComputer = class
cpu : TCPU; // связующее поле
mem : TMem; // связующее поле
// другие поля
// методы
class CPU
// поля и методы класса «Процессор»
class Memory
// поля и методы класса «Память»
class Computer
CPU cpu; // связующее поле
Memory mem; // связующее поле
// другие поля
// методы
При разработке составных классов обязательно надо продумать
механизм создания объектов таких классов. При этом возможны два
основных варианта реализации конструкторов в составных классах.
1. Конструктор составного класса должен создать все необходимые
объекты, для чего он должен вызвать конструкторы соответствующих
классов, при необходимости передавая им входные параметры и
устанавливая значение связующих объектных переменных в адреса
созданных этими конструкторами объектов. Пример для составного класса
«Компьютер»:
constructor TComputer.Create (входные параметры);
begin
cpu := TCPU.Create (…); // установка связи с создаваемым объектом
mem := TMem.Create (…); // установка связи с создаваемым объектом
// установка обычных свойств
end;
public Computer (входные параметры) {
cpu = new CPU (…); // установка связи с создаваемым объектом
mem = new Memory (…); // установка связи с создаваемым объектом
// установка обычных свойств