组成是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表示,无论是构造函数注入,setter注入还是公共属性注入。
这些都是汇总
最严格的构造函数注入(object B
没有不能存在object A
)。
final class B
{
private $a;
public function __construct(A $a)
{
$this->a = $a;
}
}
松动(您可能会或可能不会object A
在inside中使用它object B
,但是如果这样做,则可能应该先设置它)。
通过设置器:
final class B
{
private $a;
public function setA(A $a)
{
$this->a = $a;
}
}
通过公共财产:
final class B
{
public $a;
}
如果使用的只是类的具体实现,则没有什么好方法可以证明使用聚合而不是使用组合,但是一旦您开始注入接口或使用C ++抽象类,则聚合将是唯一的方法。履行您的合同。