примеры кода: https://sourcemaking.com/design_patterns/composite/php Я сделал нечто подобное, кроме этогоOnTheBookShelf
«знает около $ книг (SeveralBooks
). Мои «начальники» говорят, что плохо, что они знают друг о друге. Но почему?
Хорошо, я редактирую это:
abstract class OnTheBookShelf {
public $shelf; /////////////////////////////////////////////////
abstract function getBookInfo($previousBook);
abstract function getBookCount();
abstract function setBookCount($new_count);
abstract function addBook($oneBook);
abstract function removeBook($oneBook);
}
class OneBook extends OnTheBookShelf {
private $title;
private $author;
function __construct($title, $author) {
$this->title = $title;
$this->author = $author;
}
function getBookInfo($bookToGet) {
if (1 == $bookToGet) {
return $this->title." by ".$this->author;
} else {
return FALSE;
}
}
function getBookCount() {
return 1;
}
function setBookCount($newCount) {
return FALSE;
}
function addBook($oneBook) {
return FALSE;
}
function removeBook($oneBook) {
return FALSE;
}
}
class SeveralBooks extends OnTheBookShelf {
private $oneBooks = array();
private $bookCount;
public function __construct() {
$this->setBookCount(0);
}
public function getBookCount() {
return $this->bookCount;
}
public function setBookCount($newCount) {
$this->bookCount = $newCount;
}
public function getBookInfo($bookToGet) {
if ($bookToGet <= $this->bookCount) {
return $this->oneBooks[$bookToGet]->getBookInfo(1);
} else {
return FALSE;
}
}
public function addBook($oneBook) {
$oneBook->shelf = $this; //////////////////////////////////////////////////
$this->setBookCount($this->getBookCount() + 1);
$this->oneBooks[$this->getBookCount()] = $oneBook;
return $this->getBookCount();
}
public function removeBook($oneBook) {
$counter = 0;
while (++$counter <= $this->getBookCount()) {
if ($oneBook->getBookInfo(1) ==
$this->oneBooks[$counter]->getBookInfo(1)) {
for ($x = $counter; $x < $this->getBookCount(); $x++) {
$this->oneBooks[$x] = $this->oneBooks[$x + 1];
}
$this->setBookCount($this->getBookCount() - 1);
}
}
return $this->getBookCount();
}
}
Я добавил кучу //////////////// к проблемным линиям. И здесь говорят, что в этой книге есть ссылка на полку.
Они должны знать об их интерфейсах, чтобы их можно было изменить.
Допустим, у вас есть классы:
Bookshelf
private books: Book[]
Book
public title: String
Вы бы тогда получили доступ books[i].title
и отобразить название книги.
Теперь представьте, что программист отвечает Book
решает, что заголовок имеет свой собственный класс, поэтому мы имеем:
Book
public title: Title
Title
private t: String
public toString()
Теперь программист, который кодировал Bookshelf
требуется изменить свой код.
С другой стороны, если бы мы имели:
Book
private title: String
public getTitleString()
Тогда мы могли бы изменить реализацию Book
класс, и все, что нам нужно сделать, это написать getTitleString()
функция, которая будет возвращать строковое представление заголовка, и все будет продолжать работать без каких-либо дополнительных изменений Bookshelf
,
Мои «начальники» говорят, что плохо, что они знают друг о друге. Но почему?
Проблема круговой ссылки между Shelf
а также Book
это не так тривиально и требует особой осторожности в работе.
Например, если вы просто напишите $oneBook->shelf = $this;
внутри addBook
метод, то что произойдет, если потребитель вызывает этот метод для одной книги на двух разных полках?
$book = new Book;
$shelf1 = new Shelf;
$shelf2 = new Shelf;
$shelf1->addBook($book);
$shelf2->addBook($book);
Book
будет добавлен к обеим полкам, но он будет содержать ссылку только на последнюю полку, что приводит к несогласованности и потенциальным ошибкам во время выполнения.
Конечно, круговая ссылка может быть сделана правильно, но это требует особого внимания и усложняет код.