对象应该实现迭代器还是包含实现迭代器的另一个对象

时间:2008-10-19 06:08:26

标签: php design-patterns iterator

我正试图绕过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

}

6 个答案:

答案 0 :(得分:4)

bbxbby,最好的解决方案通常是最简单的解决方案。你绝对不会创建单独的迭代器对象。事实上,PHP支持并鼓励提供IteratorAggregate接口的此类聚合。实现IteratorAggregate的对象必须包含返回getIterator()的{​​{1}}方法。这正是您的Iterator方法所做的。关于getChocolated()的好处是你可以将它的对象直接传递给IteratorAggregate循环。您的代码在使用时可能看起来像这样:

foreach

然后,代码中的某个地方:

class BoxOfChocolates implements IteratorAggregate

    private $chocolates = array();

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

}

答案 1 :(得分:2)

这取决于具体情况。巧克力盒是否包含多个系列?如果是这样,您需要将集合作为成员。

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

我认为这属于第一组

:)

答案 2 :(得分:1)

我也建议第一组,假设你的巧克力比喻对于实际的班级非常准确。

一盒巧克力真的是你的巧克力系列,因此想要迭代那个盒子里的巧克力是有意义的。添加一个单独的巧克力列表并没有真正添加任何值,只是似乎添加了一个不必要的层。

答案 3 :(得分:0)

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

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

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

答案 4 :(得分:0)

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

答案 5 :(得分:0)

我认为你应该将你的集合与迭代器分开。我同意@James Curran的观点,即集合通常都有迭代器 - 事实上,它们可能有几个。例如,你可能想要一个用坚果跳过糖果的迭代器(虽然典型的情况是想要一个反转顺序的人)。在这种情况下,next()方法的含义会发生变化。要处理它,请在包含自己的迭代语义的单独类中实现迭代器。提供集合中的方法以获取正确排序的迭代器。这确实是一个关注点分离的问题。该集合并不关心用户如何迭代它,这就是迭代器的关注点。