php迭代器模式,PHP迭代器模式与环形链表

迭代器模式,并不在最初的23个设计模式中。但是,对于PHP,由于它的数组支持不同的数据类型,所以,PHP中少了很多静态数据类型。并且,forech的强大,以致于初级用户想不到使用迭代器模式。

迭代器模式,PHP提供了多种实现方式。其一是SPL。

在SPL中,我们有:Countable,  ArrayAccess, Iterator 这三个接口。通过这三个接口,我们可以把一个类,当成数组来使用。这是最简单的迭代器模式。(大家可以查一下PHP手册中关于Countable,  ArrayAccess, Iterator的例子)

有人要问,为什么要用迭代器模式呢?道理很简单,如果你的foreach中的代码很长,并且,多个这样的代码且很多类似的地方。那么,你就可以用类的方式来实现,从而把具体的放到类中,通过继承实现具体的算法。

比如,下面一个例子,是生成一组 YYYY-MM-DD 的键值,从而到查询结查中获取对应的数据。用这个类,封装了KEY的生成。此类中实现的就是SPL的Iterator接口

namespace MyData\Models\Iterators;

use Carbon\Carbon;

use Iterator;

/**

* Class KeyIterator

* @package MyData\Models\Iterators

*/

class KeyIterator implements Iterator

{

/**

* Order type of array

* 顺序:下一条记录,加1

*/

const ORDER_ASC  = 1;

/**

* Order type of array

* 倒序:上一条记录,减1

*/

const ORDER_DESC = -1;

/**

* 用于生成数组KEY的data format

*/

const DATE_FORMAT = 'Y-m-d';

/** @var  Carbon */

private $keyDate;

/**

* @var

*/

private $orderType;

/**

* @var

*/

private $itemCount;

/**

* @var

*/

private $position;

/**

* @var int

*

* 是否显示最近一个月,默认不显示,

* 因为,当前月份一般可能是没有数据!!

*

*/

private $showRecent = 0;

/**

* KeyIterator constructor.

* @param $orderType

* @param int $itemCount

*/

private function __construct($orderType,$itemCount=132)

{

$this->orderType = $orderType;

$this->itemCount = $itemCount;

}

/**

* @param $orderBy

* @param $itemCount

* @return static

*/

public static function of($orderBy,$itemCount){

return new static($orderBy,$itemCount);

}

/**

* @return int

*/

public function count(){

return $this->itemCount;

}

private function reset() {

$this->keyDate = now()->setDay(1)->subMonths($this->itemCount-$this->showRecent);

}

private function end(){

$this->keyDate = now()->setDay(1)->subMonths(abs($this->showRecent-1));

}

/**

* @return mixed

*/

public function rewind() {

$this->position = 0;

if(self::ORDER_ASC === $this->orderType){

$this->reset();

}else{

$this->end();

}

return $this->keyDate->format(self::DATE_FORMAT);

}

/**

* @return mixed

*/

public function current() {

return $this->keyDate->format(self::DATE_FORMAT);

}

/**

* @return mixed

*/

public function key() {

return $this->position;

}

/**

* @return mixed

*/

public function next() {

$this->position++;

if($this->position >= $this->itemCount){

return false;

}

if(self::ORDER_ASC === $this->orderType){

$this->keyDate = $this->keyDate->addMonth();

}else{

$this->keyDate = $this->keyDate->subMonth();

}

return $this->keyDate->format(self::DATE_FORMAT);

}

/**

* @return mixed

*/

public function prev(){

$this->position--;

if($this->position 

return false;

}

if(self::ORDER_ASC === $this->orderType){

$this->keyDate = $this->keyDate->subMonth();

}else{

$this->keyDate = $this->keyDate->addMonth();

}

return $this->keyDate->format(self::DATE_FORMAT);

}

/**

* @return bool

*/

public function valid() {

return $this->positionitemCount;

}

}

有了上面这个类,我们就可以:

Php代码

$keyItems = KeyIterator::of($this->orderType,$this->fetchCount);

//上面是迭代器对象,所以,直接用foreach

foreach($keyItems as $key => $itemKey){

//直接用生成的$itemKey去读取源数据

$outArray[$key] = $sourceArray[$itemKey]

}

迭代器,可以帮助我们把具体的算法放到类中,从而可以使代码可读性增强,且使得代码可维护。

同样,迭代器模式,还能让我们的减少使用foreach。这是因为,我们可以通过类的结构,把算法结构化。

现在,PHP中又增加了yield这个生成器函数。使得迭代器模式变得更加方便。

比如,我们要做一个环形双向链表。当然,有人会问,这个有什么用?

其实,用到的地方还是很多的。比如,  我们在WINDWS任务管理器中,能够看到动态显示的性能图表。这个图表,如果用环形链表,就相当方便。

再如,涉及地理多边形计算时,我们也需要用到环形链表。

这里我们推荐一个环形链表开源。是基于yield实现的。

此组件拥有以下特性:

支持带接头的数组。比如地理数据多边形就有接头,最后一个元素与第一个是相同的。最后一个就是接头。

支持元素更新,查找,插入,移除,添加等操作。

支持顺序迭代 nextItems() 与逆序迭代 prevItems(),

支持多圈迭代 nextItemsWithCount() prevItemsWithCout(),

支持任意整数的开始位置与结束位置

具有双向链表完全特性,可以通过,nextItem()和prevItem() 获取前一元素以下后面元素。nextKey()和prevKey() 获以前一元素和后一元素的Key

支持队列所需的特性,具有push,pop,shift,unshift操作,且队列也支持接头

这个项目,仅有一个类。且连注解在内,整个类只有400行。我们不得不感叹PHP语言的强大。它不需要复杂的数据结构,但当我们需要使用时,我们可以用极简的代码实现我们所要的数据结构的类。相比JAVA, C++, 这些语言,你要了解 ArrayList, TreeMap , HashMap, Vertor, ...等一堆数据结构,PHP确实简单且方便多了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值