我正在阅读一篇关于 OOP、关联、组合、聚合等关系的文章。有些内容令人困惑,而且我不断在网上找到相互矛盾的信息,所以我希望有人能对此有所启发。
因此,在 PHP 中,我们将以下代码称为组合,并且许多文章/教程指出使用组合而不是继承。
class A
{
}
class B
{
public function __construct(protected A $a)
{
}
}
Run Code Online (Sandbox Code Playgroud)
读了几篇关于组合和聚合的文章后,似乎上面实际上是聚合而不是组合的示例,因为在组合中,类 A 的对象不能离开类 B 而存在,所以当类 B 的对象被销毁时,该对象A类的也应该被销毁。上面代码中的情况显然不是这样,因为类 A 的对象可以存在于类 B 之外,因此它的生命周期不依赖于类 B。
以下是组合的示例:
class B
{
public A $a;
public function __construct()
{
$this->a = new A();
}
}
Run Code Online (Sandbox Code Playgroud)
因此,根据我的理解,聚合意味着A类的对象可以存在于B类之外,而组合意味着A类的对象的生命周期依赖于B类并且不能存在于B类之外。
我的理解正确吗?
重要的是要记住,这些是关联类和对象的模式。
我要说的第一点是,任何像“使用组合而不是继承”这样的一揽子规则都反映了一些缺失的上下文。如果合适的话使用继承。
这些其他模式用于将类关联在一起。
聚合通常用于层次结构/父/子关系。
一个典型的例子是将员工和部门关联起来。
因此,为了对此进行建模,Department 通常会有一个内部员工[] 数组。
相反,员工可以在内部存储部门对象。这本质上匹配两个类之间的关系,如 Many >-< Many。
组合反映了更严格的父/子关系,这意味着对象 A 由 1-N 个对象 B 组成。
组合关系的典型示例是购物车,其中包含 0-N 个产品系列项目。
假设有 Cart 和 Lineitem 类,Cart 将存储 Lineitem 数组。
聚合和组合之间的主要区别在于,对于组合,如果购物车被销毁,则所有关联的 Lineitem 对象都应该被销毁。
以聚合为例,如果删除一个部门,并不一定意味着所有聚合的员工都会被删除,而是删除一个部门只会破坏员工和部门之间的关系,并且可能需要存储员工的部门对象将为空,直到员工被分配到另一个部门,或者他们的雇佣关系结束。
实际上,由于 PHP 是页面范围的,因此变量和对象组合的生命周期很短,因此您实际上不会在 ORM 之外找到使用这些 UML 模式的许多情况。数据需要持久化,通常这种持久化是通过某种 RDBMS 或文档数据库实现的,其中 ORM 将模拟表之间的关系,或者可能是层次结构。
以你的例子为例:
这些 foo/bar A/B 示例没有语义或价值。示例 #1 中的唯一机制是 ObjB 必须首先是 ObjA,否则无法构造。您提供的语法是 PHP8 中的新语法,我一开始就错过了。
看来这个例子更可能需要是:
class A
{
private bSet = array();
public function addB(B $b) {
$this->bSet[] = new B($this);
}
}
class B
{
private $a;
public function __construct(A $a)
{
$this->a = $a;
}
}
// B shouldn't be made without a Parent A
$objA = new A();
$objA->addB();
$objA->addB();
Run Code Online (Sandbox Code Playgroud)
然而,从技术上讲,没有什么可以阻止你获得 B,因为构造函数始终是公共的。
$objB = new B($objA);
Run Code Online (Sandbox Code Playgroud)
通过聚合,这将是更可能的情况:
class A
{
private bSet = array();
public function addB(B $b) {
$this->bSet[] = $b;
$b->setA($this);
}
public function delB(B $b) {
for ($i=0; $i < count($this->bSet); $i++) {
if ($b === $this->bSet[$i]) {
unset($this->bSet[$i];
break;
}
}
}
}
class B
{
private $a;
public function setA(A $a) {
if ($this->a) {
$this->a->delB($this);
}
$this->a = $a;
}
public function getA() {
return $this->a;
}
}
$objA1 = new A();
$objA2 = new A();
$objB1 = new B();
$objB2 = new B();
$objB3 = new B();
$objA1->addB($objB2);
$objA2->addB($objB1);
$objA2->addB($objB3);
//Change $objB3's parent from A1 to A2.
$objB3->setA($objA1);
Run Code Online (Sandbox Code Playgroud)
A 和 B 彼此独立,但仍拥有所有权。
我发现 PHP 开发中更具有实际价值的是依赖注入作为领先 PHP 框架(Symfony、Laravel)的基础,以及其他常见 OOP 设计模式的实现,您可以在 Gang of 4 书、领域驱动设计或其他书籍中找到这些模式。这些天的书籍和网站。
| 归档时间: |
|
| 查看次数: |
1405 次 |
| 最近记录: |