Композиція - це коли 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;
}
Насправді не існує чудового способу виправдати використання агрегації над складом, якщо все, що ви використовуєте, є конкретними реалізаціями класів, але як тільки ви почнете вводити інтерфейси або у випадку абстрактних класів C ++, раптом агрегація стане єдиним способом виконати свій договір.