【问题标题】:Should an object implement an iterator or contain another object that implements an iterator一个对象应该实现迭代器还是包含另一个实现迭代器的对象
【发布时间】:2010-09-17 23:34:47
【问题描述】:

我正在尝试了解 SPL 迭代器,我想出了 2 种方法来处理它。我认为第一个版本不那么复杂,但第二个版本有作曲的感觉(我认为)。

我没有看到哪一个比另一个更可取?还是我把事情复杂化了?

以下是我的想法:

对象实现了一个迭代器:

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 design-patterns iterator


    【解决方案1】:

    bbxbby,最好的解决方案通常是最简单的。您绝对不会使创建单独的迭代器对象的事情变得过于复杂。事实上,PHP 支持并鼓励这种聚合提供IteratorAggregate 接口。实现IteratorAggregate 的对象必须包含返回IteratorgetIterator() 方法。这确实是您的 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) { ... }
    

    【讨论】:

      【解决方案2】:

      视情况而定。 t0 巧克力盒是否包含多个系列?如果是这样,您需要让集合成为成员。

      这样想。一盒巧克力是一个集合(即 PersonList)还是拥有一个集合的东西(即汽车可能拥有它的最后一个所有者的集合)。

      我认为这属于第一组

      :)

      【讨论】:

        【解决方案3】:

        我也建议第一组,假设你的巧克力比喻与实际班级相当准确。

        一盒巧克力确实是您收集的巧克力,因此想要迭代该盒子中的巧克力是有意义的。添加一个单独的巧克力列表并没有真正增加任何价值,而且似乎只是增加了一个不必要的层。

        【讨论】:

          【解决方案4】:

          好吧,我不懂 PHP,所以我无法正确回答这个问题,但我会尝试将它与我知道的领域联系起来。

          在 C# 中,有两个接口:IEnumerable 和 IEnumerator。在您的示例中,BoxOfChocolates 将是 Enumerable,Chocolates 将是 Enumerator。

          Enumerables 只有一个返回 Enumerator 的方法。枚举器有一个当前项目的概念,以及移动到下一个项目的方法。在大多数情况下,Enumerator 类不是“可见”的。例如,在“foreach(Chocolate item in boxOfChoclates)”这一行中,boxOfChocolates 是一个 Enumerable; Enumerator 对象被 foreach 完全隐藏。

          【讨论】:

            【解决方案5】:

            很简单,容器就是实现迭代器的地方。

            【讨论】:

              【解决方案6】:

              我认为您应该将集合与迭代器分开。我同意@James Curran 的观点,即集合通常有迭代器——事实上,它们可以有几个。例如,您可能想要一个跳过带有坚果的糖果的迭代器(尽管典型的情况是想要一个颠倒顺序的迭代器)。在这种情况下, next() 方法的含义发生了变化。为了解决这个问题,在包含它们自己的迭代语义的单独类中实现迭代器。在集合中提供方法以获得正确排序的迭代器。这实际上是一个关注点分离的问题。集合不关心用户如何迭代它,这是迭代器的关注点。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2018-03-14
                • 1970-01-01
                • 2016-12-06
                • 2015-09-09
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多