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

Я пытаюсь разобраться в итераторах 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

}
Laravel с Turbo JS
Laravel с Turbo JS
Turbo - это библиотека JavaScript для упрощения создания быстрых и высокоинтерактивных веб-приложений. Она работает с помощью техники под названием...
Аутсорсинг разработки PHP для индивидуальных веб-решений
Аутсорсинг разработки PHP для индивидуальных веб-решений
Услуги PHP-разработки могут быть экономически эффективным решением для компаний, которые ищут высококачественные услуги веб-разработки по доступным...
Еще один бенчмарк PHP
Еще один бенчмарк PHP
Сегодня я наткнулся на забавный пост на r/ProgrammerHumor, который заставил меня задуматься об одной вещи, которая меня всегда интересовала....
Преобразование данных с помощью красноречивых аксессоров и мутаторов в Laravel
Преобразование данных с помощью красноречивых аксессоров и мутаторов в Laravel
Laravel поставляется с мощной функцией под названием "Eloquent Accessors and Mutators".
Настройка PHP-проекта на MacOS: простое руководство для начинающих
Настройка PHP-проекта на MacOS: простое руководство для начинающих
PHP, широко используемый язык сценариев с открытым исходным кодом, необходим для веб-разработки. Его совместимость с MacOS делает его популярным...
Конечные и Readonly классы в PHP
Конечные и Readonly классы в PHP
В прошлом, когда вы не хотели, чтобы другие классы расширяли определенный класс, вы могли пометить его как final.
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) { ... }

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