如果物品知道容器,为什么不好?复合模式(2 个对象相互引用)php


Why is it bad if items knows about container? Composite pattern (2 objects has references to each other) php

他们说当对象具有循环引用时,这不是一个好主意。让我们看一个复合示例:

class Book
{
    private $title;
    public function __construct($title)
    {
         $this->title = $title;
    }
    public function getTitle()
    {
        return $this->title;
    }
}
class Shelf
{
    private $books = [];
    public function addBook (Book $book)
    {
         $this->books[] = $book;
    }
}
$shelf = new Shelf();
$sehlf->add (new Book('a'));
$sehlf->add (new Book('b'));
$sehlf->add (new Book('c'));

目前为止,一切都好。出于某种原因,Book必须了解Shelf,所以我重写:

class Book
{
    private $title;
    private $shelf;
    public function __construct($title, $shelf)
    {
         $this->shelf = $shelf;
         $this->title = $title;
    }
    public function getTitle()
    {
        return $this->title;
    }
}
class Shelf
{
    private $books = [];
    public function addBook (Book $book)
    {
         $this->books[] = $book;
    }
}
$shelf = new Shelf();
$sehlf->add (new Book('a', $shelf));
$sehlf->add (new Book('b', $shelf));
$sehlf->add (new Book('c', $shelf));

他们说这很糟糕。

循环引用有几个问题可以在这里找到,但我必须接受上面不是一个非常有问题的例子——因为很明显,在书之前必须先创建书架。

例如,最常见的问题之一是,假设变量是公共的,在上述Book实例上使用print_r可能是"不可能的",这将导致内存耗尽。

有几种方法可以解决循环引用问题,最常见的方法之一是使用 Setter 注入。

例如
public function setShelf(Shelf $shelf)
{
    $this->shelf = $shelf;
}

PHP 的另一个特别问题是,它可能在解决循环依赖关系时遇到问题。例如,请参阅此内容。

class Node {
    public $parentNode;
    public $childNodes = array();
    function Node() {
        $this->nodeValue = str_repeat('0123456789', 128);
    }
    function destroy()
    {
        $this->parentNode = null;
        $this->childNodes = array();
    }
}
function createRelationship() {
    $parent = new Node();
    $child = new Node();
    $parent->childNodes[] = $child;
    $child->parentNode = $parent;
    $parent->destroy();
}

PHP 最终会无缘无故地分配大约 35MB 的内存。为了解决这个问题,我们可以使用析构函数,以便垃圾回收器知道如何在完成对象后处理对象。

function destroy()
{
    $this->parentNode = null;
    $this->childNodes = array();
}