如何根据 PHP 中的编程最佳实践实现这一点


How to implement this in accordance with the programming best practice in PHP

为了描述我的问题,我将使用某些类比,该类比更容易进行分析,并且在我看来很好地反映了我的问题。

假设有一个 Library 类,它包含两个列表:书籍列表和书架列表。在PHP中,两个列表最容易实现为数组,我这样做了 - 我在类Library中创建了两个公共字段:书籍和书架,在构造函数中,我用数组初始化了它们。

class Library
{
    public $books;
    public $bookshelves;
    public function __construct () {
        $this->books = array();
        $this->bookshelves = array();
    }
}

一切都会好起来的,因为在数组中实现的方法就足够了。但从编程最佳实践的角度来看,这段代码对我来说似乎是不正确的。我觉得这个班级不是那么封闭,是吗?有必要记住该字段的用途以及如何对待他。例如,如果我想将书籍添加到库中,我会在图书馆类中搜索方法addBook。我从来没有想过我必须在图书馆类的现场书籍上执行方法添加。

因此,我应该将书籍和书架字段作为私有字段,并在 Library 类中实现函数 addBook/addBookshelf、removeBook/removeBookshelf、getBook/getBookshelf 等。

class Library
{
    private $books;
    private $bookshelves;
    public function __construct () {
        $this->books = array();
        $this->bookshelves = array();
    }
    public function addBook (Book $book) {
        $this->books[] = $book;
    }
    public function removeBook ($id) {
        $this->books[$id] = [];
    }
    public function getBook ($id) {
        return $this->books[$id];
    }
    public function addBookhelf (Book $book) {
        $this->bookshelf[] = $book;
    }
    public function removeBookhelf ($id) {
        $this->bookshelf[$id] = [];
    }
    public function getBookhelf ($id) {
        return $this->bookshelf[$id];
    }
}

但这也是不正确的。为什么有人会花时间第二次编写已经在数组中实现的相同内容?而原则是什么,一个阶级,一个责任?

第三种方法是创建两个类:BooksList 和 Bookshelf List,它们扩展了 ArrayObject 类。它们没有任何其他方法或字段。

class BooksList extends ArrayObject
{
}
class BookshelvesList extends ArrayObject
{
}

接下来,我应该使用此类初始化公共字段书籍和书架。

class Library
{
    private $books;
    private $bookshelves;
    public function __construct ()
    {
        $this->books = new BooksList();
        $this->bookshelves = new BookshelvesList();
    }
}

然后,图书馆类不负责对书籍和书架的操作。数组操作不会第二次写入。但是正在创造两个奇怪的物体,它们并没有增加新的东西。

所以我发明了三种实现我的问题的可能性,但每种都有一些缺陷。这不是一些复杂的关系,实现这一点将是简单而优雅的方式。我寻找了一些适合这个问题的设计模式,但没有找到。因此,我在这里问,如何正确实现这一点?

只是回答你的一个问题:

为什么有人会花时间第二次编写已经在数组中实现的相同内容?

如果你只是原型或其他东西,你可能不会。但大多数时候,最好能够控制对对象中关键数据的访问。它为您提供了保护,防止代码在以后被滥用(例如,有人将Tree对象直接添加到您的$books数组中 - 您可以在addBook函数中添加验证以轻松防止这种情况)。其次,它为您提供了更大的灵活性。如果客户突然决定每次将一本书添加到藏书中时,他们都希望向图书管理员发送电子邮件怎么办?如果你允许你的代码从任何地方直接添加一个公共变量,你可能还有相当多的维护工作摆在你面前!