Агрегация

Пример. Отношение агрегации между классами имеет непосредственное отношение к агрегации между их экземплярами. Рассмотрим вновь класс TemperatureController:

class TemperatureController {
public:

TemperatureController(Location);
~TemratureController();
void process(const TemperatureRamp&);
Minute schedule(const TemperatureRamp&) const;

private:

Heater h;

};

Рис. 3-8. Агрегация.

Как явствует из рис. 3-8, класс TemperatureController это, несомненно, целое, а экземпляр класса Heater - одна из его частей. Совершенно такое же отношение агрегации между экземплярами этих классов показано на рис. 3-3.

Физическое включение. В случае класса TemperatureController мы имеем агрегацию по значению; эта разновидность физического включения означает, что объект класса Heater не существует отдельно от объемлющего экземпляра класса TemperatureController.

Менее обязывающим является включение по ссылке. Мы могли бы изменить закрытую часть TemperatureController так [В качестве альтернативы мы могли бы описать h как ссылку на нагреватель (Heater& в C++), в этом случае семантика инициализации и модификации этого объекта будет совершенно отличной от семантики указателей]:

Heater* h;

В этом случае класс TemperatureController по-прежнему означает целое, но его часть, экземпляр класса Heater, содержится в целом косвенно. Теперь эти объекты живут отдельно друг от друга: мы можем создавать и уничтожать экземпляры классов независимо. Чтобы избежать структурной зависимости через ссылки важно придерживаться какой-то договоренности относительно создания и уничтожения объектов, ссылки на которые могут содержаться в разных местах. Нужно, чтобы это делал кто-то один.

Агрегация является направленной, как и всякое отношение "целое/часть". Объект Heater входит в объект TemperatureController, и не наоборот. Физическое вхождение одного в другое нельзя "зациклить", а вот указатели - можно (каждый из двух объектов может содержать указатель на другой).

Конечно, как уже говорилось, агрегация не требует обязательного физического включения, ни по значению, ни по ссылке. Например, акционер владеет акциями, но они не являются его физической частью. Более того, время жизни этих объектов может быть совершенно различным, хотя концептуально отношение целого и части сохраняется и каждая акция входит в имущество своего акционера. Поэтому агрегация может быть очень косвенной. Например, объект класса Shareholder (акционер) может содержать ключ записи об этом акционере в базе данных акций. Это тоже агрегация без физического включения. "Лакмусовая бумажка" для выявления агрегации такова: если (и только если) налицо отношение "целое/часть" между объектами, их классы должны находиться в отношении агрегации друг с другом.

Рис. 3-9. Отношение использования.

Часто агрегацию путают с множественным наследованием. Действительно, в C++ скрытое (защищенное или закрытое) наследование почти всегда можно заменить скрытой агрегацией экземпляра суперкласса. Решая, с чем вы имеете дело - с наследованием или агрегацией - будьте осторожны. Если вы не уверены, что налицо отношение общего и частного (is а), вместо наследования лучше применить агрегацию или что-нибудь еще.