Композиция - это когда object A
содержит object B
и object A
также несет ответственность за создание object B
.
Композиционные отношения
У нас есть класс A, который будет использоваться классом B.
final class A
{
}
Есть несколько вариантов того, как может выглядеть композиция.
Прямая инициализация композиции:
final class B
{
private $a = new A();
}
Состав инициализации конструктора
final class B
{
private $a;
public function __construct()
{
$this->a = new A();
}
}
Ленивая инициализация композиции
final class B
{
private $a = null;
public function useA()
{
if ($this->a === null) {
$this->a = new A();
}
/* Use $this->a */
}
}
Вы видите, что это создает тесные отношения между классами A
и B
. Класс B
просто не может существовать без A
. Это огромное нарушение принципа внедрения зависимостей , которое гласит:
Зависимость - это объект, который можно использовать (сервис). Инъекция - это передача зависимости зависимому объекту (клиенту), который будет ее использовать. Услуга является частью состояния клиента. Передача сервиса клиенту, а не предоставление клиенту возможности создавать или находить сервис, является фундаментальным требованием шаблона.
Композиция иногда имеет смысл, например, вызов new DateTime
в php или new std::vector<int>
в C ++. Но чаще всего это предупреждение о том, что ваш код написан неправильно.
В случае, когда class A
будет специальным объектом, используемым для кэширования, class B
он всегда будет кэшироваться с использованием реализации class A
, и у вас не будет контроля для его динамического изменения, что плохо.
Кроме того, если вы использовали ленивую композицию инициализации , то есть у вас есть рабочий object B
, называемый useA()
методом и созданиемobject A
не удастся, ваш файл object B
внезапно окажется бесполезным.
Агрегация, с другой стороны, является способом взаимоотношений, который следует принципу DI . object B
необходимо использовать object A
, то вы должны передать уже созданный экземпляр object A
дляobject B
, и если создание object A
завершится ошибкой, ничего не будет передано в первую очередь.
Короче, Агрегация - это представление UML для принципа внедрения зависимостей , будь то внедрение конструктора, установка сеттера или внедрение открытого свойства.
Это все агрегации
Самая тесная инъекция в конструктор ( object B
не может существовать без object A
).
final class B
{
private $a;
public function __construct(A $a)
{
$this->a = $a;
}
}
Слабее (вы можете или не можете использовать object A
внутри object B
, но если вы это сделаете, вы, вероятно, должны установить его первым).
Через сеттер:
final class B
{
private $a;
public function setA(A $a)
{
$this->a = $a;
}
}
Через общественную собственность:
final class B
{
public $a;
}
На самом деле нет хорошего способа оправдать использование Aggregation over Composition, если все, что вы используете, - это конкретные реализации классов, но как только вы начнете внедрять интерфейсы или в случае абстрактных классов C ++, внезапно Aggregation станет единственным способом выполнить ваш контракт.