Kompozycja ma miejsce, gdy object A
zawiera object B
i object A
jest również odpowiedzialna za tworzenie pliku object B
.
Relacja składu
Mamy klasę A, która będzie używana przez klasę B.
final class A
{
}
Istnieje wiele opcji, takich jak wygląd kompozycji.
Skład bezpośredniej inicjalizacji:
final class B
{
private $a = new A();
}
Kompozycja inicjalizacji konstruktora
final class B
{
private $a;
public function __construct()
{
$this->a = new A();
}
}
Leniwa kompozycja inicjalizacyjna
final class B
{
private $a = null;
public function useA()
{
if ($this->a === null) {
$this->a = new A();
}
/* Use $this->a */
}
}
Widzisz, tworzy to ścisły związek między klasami A
i B
. Klasa B
po prostu nie może istnieć bez A
. Jest to ogromne naruszenie zasady wstrzykiwania zależności , która mówi:
Zależność to obiekt, z którego można korzystać (usługa). Zastrzyk to przekazanie zależności do obiektu zależnego (klienta), który go użyje. Usługa jest częścią stanu klienta. Podstawowym wymaganiem wzorca jest przekazanie usługi klientowi, zamiast umożliwienia klientowi zbudowania lub znalezienia usługi.
Kompozycja czasami ma sens, na przykład wywoływanie new DateTime
w php lub new std::vector<int>
w C ++. Ale najczęściej jest to ostrzeżenie, że Twój projekt kodu jest nieprawidłowy.
W przypadku, gdy class A
byłby to specjalny obiekt używany do buforowania, class B
zawsze byłby buforowany przy użyciu implementacji class A
i nie miałbyś żadnej kontroli, aby dynamicznie go zmieniać, co jest złe.
Ponadto, jeśli użyjesz leniwej kompozycji inicjalizacyjnej , co oznacza, że będziesz miał działającą metodę object B
, zwaną useA()
metodą, a tworzenie się object A
nie powiedzie, twoja object B
nagle stanie się bezużyteczna.
Z drugiej strony agregacja jest sposobem relacji, który jest zgodny z zasadą DI . object B
musi użyć object A
, to powinieneś przekazać już utworzoną instancję object A
do object B
, a jeśli tworzenie się object A
nie powiedzie, nic nie zostanie przekazane w pierwszej kolejności.
W skrócie, Agregacja jest reprezentacją UML dla zasady wstrzykiwania zależności , czy to wstrzykiwania do konstruktora, wstrzykiwania setera czy wstrzykiwania własności publicznej.
To są wszystkie agregacje
Najściślejszy wtrysk konstruktora ( object B
nie może istnieć bez object A
).
final class B
{
private $a;
public function __construct(A $a)
{
$this->a = $a;
}
}
Looser (możesz lub nie możesz używać w object A
środku object B
, ale jeśli to zrobisz, prawdopodobnie powinieneś go najpierw ustawić).
Za pomocą setera:
final class B
{
private $a;
public function setA(A $a)
{
$this->a = $a;
}
}
Za pośrednictwem własności publicznej:
final class B
{
public $a;
}
Nie ma naprawdę świetnego sposobu na uzasadnienie użycia Agregacji zamiast Kompozycji, jeśli wszystko, czego używasz, to konkretne implementacje klas, ale kiedy zaczniesz wstrzykiwać interfejsy lub w przypadku klas abstrakcyjnych C ++, nagle Agregacja będzie jedynym sposobem na wypełnij swój kontrakt.