Thành phần là khi một object A
chứa object B
và object A
cũng chịu trách nhiệm tạo ra object B
.
Mối quan hệ thành phần
Chúng tôi có một lớp A sẽ được sử dụng bởi lớp B.
final class A
{
}
Có nhiều lựa chọn như cách bố cục có thể trông.
Thành phần khởi tạo trực tiếp:
final class B
{
private $a = new A();
}
Thành phần khởi tạo xây dựng
final class B
{
private $a;
public function __construct()
{
$this->a = new A();
}
}
Thành phần khởi tạo lười biếng
final class B
{
private $a = null;
public function useA()
{
if ($this->a === null) {
$this->a = new A();
}
/* Use $this->a */
}
}
Bạn thấy điều này tạo ra một mối quan hệ chặt chẽ giữa các lớp A
và B
. Lớp B
chỉ đơn giản là không thể tồn tại mà không có A
. Đây là một vi phạm lớn của nguyên tắc tiêm phụ thuộc , trong đó nói:
Một phụ thuộc là một đối tượng có thể được sử dụng (một dịch vụ). Một mũi tiêm là việc truyền một phụ thuộc vào một đối tượng phụ thuộc (một khách hàng) sẽ sử dụng nó. Dịch vụ này là một phần của trạng thái của khách hàng. Truyền dịch vụ cho khách hàng, thay vì cho phép khách hàng xây dựng hoặc tìm dịch vụ, là yêu cầu cơ bản của mẫu.
Thành phần đôi khi có ý nghĩa, chẳng hạn như gọi new DateTime
bằng php hoặc new std::vector<int>
trong C ++. Nhưng thường xuyên hơn không, đó là một cảnh báo, rằng thiết kế mã của bạn là sai.
Trong trường hợp, trong đó class A
đối tượng sẽ là một đối tượng đặc biệt được sử dụng để lưu vào bộ đệm, thì đối tượng class B
đó sẽ luôn được lưu trong bộ đệm khi sử dụng class A
và bạn sẽ không có quyền kiểm soát để thay đổi động nó, điều này rất tệ.
Ngoài ra, nếu bạn sử dụng thành phần khởi tạo lười biếng , có nghĩa là bạn sẽ có một tác phẩm object B
, được gọi là useA()
phương thức và việc tạo ra object A
sẽ thất bại, bạn object B
đột nhiên vô dụng.
Tập hợp, mặt khác, là một cách của mối quan hệ, theo nguyên tắc DI . object B
nhu cầu để sử dụng object A
, sau đó bạn phải vượt qua đã tạo thể hiện của object A
để object B
, và cần sự sáng tạo của object A
Fail, không có gì sẽ được thông qua ở nơi đầu tiên.
Nói tóm lại, Uẩn là đại diện UML cho nguyên tắc tiêm phụ thuộc , có thể là tiêm xây dựng, tiêm setter hoặc tiêm sở hữu công cộng.
Đây là tất cả các Uẩn
Các tiêm xây dựng chặt chẽ nhất ( object B
không thể tồn tại mà không có object A
).
final class B
{
private $a;
public function __construct(A $a)
{
$this->a = $a;
}
}
Looser (bạn có thể hoặc không thể sử dụng object A
bên trong object B
, nhưng nếu bạn làm vậy, có lẽ bạn nên đặt nó trước).
Qua setter:
final class B
{
private $a;
public function setA(A $a)
{
$this->a = $a;
}
}
Thông qua tài sản công cộng:
final class B
{
public $a;
}
Thực sự không có cách nào tuyệt vời để biện minh cho việc sử dụng Tập hợp trên Thành phần, nếu tất cả những gì bạn đang sử dụng là triển khai cụ thể các lớp, nhưng một khi bạn bắt đầu tiêm giao diện hoặc trong trường hợp các lớp trừu tượng C ++, đột nhiên Tập hợp sẽ là cách duy nhất để thực hiện hợp đồng của bạn