Если объект реализует итератор или содержит другой объект, реализующий итератор

Я пытаюсь разобраться в итераторах SPL, и я придумал два способа справиться с этим. Я считаю, что первая версия менее сложна, но вторая версия имеет композиционный характер (я думаю).

Чего я не вижу, какой из них предпочтительнее другого? Или я просто слишком усложняю это?

Вот мои мысли:

Объект реализует итератор:

class BoxOfChocolates implements Iterator {

  private $id
  private $name; // e.g. Valentine's Heart Box
  private $maker; // e.g. Hersheys
  private $items; // array

  public function getChocolates() {
    $query = ...
    foreach($rows as $row) {
      $this->_items[] = new Chocolate() ...
    }
  }

  // ... necessary iterator implementation stuff


}

Объект содержит объект с возможностью итерации:

class BoxOfChocolates {

  private $id;
  private $name;
  private $maker;
  private $items; // chocolates object

  public function getChocolates() {
    $this->items = new Chocolates();
    $this->items->getChocolates();
  }

}


class Chocolates implements Iterator {

  private $items;

  public function getChocolates() {
    $query = ...
    foreach($rows as $row) {
      $this->_items[] = new Chocolate() ...
    }
  }

  // ... necessary iterator implementation stuff

}
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
5
0
813
6

Ответы 6

Это зависит от ситуации. Коробка конфет будет содержать несколько коллекций? В таком случае вам нужно, чтобы коллекции были членами.

Подумайте об этом так. Коробка конфет - это коллекция (например, PersonList) или что-то, что владеет коллекцией (например, автомобиль может владеть коллекцией своих последних владельцев).

Я думаю, это относится к первой группе

:)

Я бы посоветовал и первую группу, если предположить, что ваша метафора о шоколаде довольно точна для реального класса.

коробка конфет - это действительно ваша коллекция конфет, и поэтому имеет смысл перебирать конфеты внутри этой коробки. добавление отдельного списка шоколада на самом деле не добавляет никакой ценности, а просто добавляет ненужный слой.

Ну, я не знаю PHP, поэтому я не могу правильно ответить на вопрос, но я попробую связать его с областью, которую я знаю.

В C# есть два интерфейса: IEnumerable и IEnumerator. В вашем примере BoxOfChocolates будет Enumerable, Chocolates будет Enumerator.

Enumerables просто имеют метод, который возвращает Enumerator. У счетчиков есть понятие текущего элемента и средства перехода к следующему элементу. В большинстве случаев класс Enumerator не «виден». Например, в строке «foreach (шоколадный элемент в boxOfChoclates)» boxOfChocolates является Enumerable; объект Enumerator полностью скрыт функцией foreach.

Проще говоря, контейнер - это место для реализации итератора.

Я думаю, вам следует хранить свои коллекции отдельно от итераторов. Я согласен с @James Curran, что в коллекциях часто есть итераторы - на самом деле, их может быть несколько. Например, вам может понадобиться итератор, который пропускает конфеты с орехами (хотя в типичном случае нужен итератор, который меняет порядок). В этом случае смысл метода next () меняется. Чтобы справиться с этим, реализуйте итераторы в отдельных классах, которые содержат свою собственную семантику итераций. Предоставьте в коллекции методы для получения итераторов правильного вида. Это действительно проблема разделения интересов. Коллекцию не волнует, как пользователь перебирает ее, это забота итератора.

bbxbby, лучшее решение - обычно самое простое. Вы определенно не слишком усложняете создание отдельного объекта-итератора. Фактически, PHP поддерживает и поощряет такое агрегирование, предоставляя интерфейс IteratorAggregate. Объекты, реализующие IteratorAggregate, должны содержать метод getIterator(), возвращающий Iterator. Это действительно то, что делает ваш метод getChocolated(). Хорошая особенность IteratorAggregate заключается в том, что вы можете передать его объект непосредственно в цикл foreach. При использовании ваш код может выглядеть так:

class BoxOfChocolates implements IteratorAggregate

    private $chocolates = array();

    public function getIterator() {
        return new ArrayIterator(new ArrayObject($this->chocolates)));
    }

}

А затем где-то в коде:

$box = new BoxOfChocolates();
foreach ($box as $chocolate) { ... }

Другие вопросы по теме