《PHP设计模式介绍》第八章 迭代器模式_PHP教程
推荐:《PHP设计模式介绍》第七章 策略模式在编写面向对象的代码的时,有些时候你需要一个能够自己根据不同的条件来引入不同的操作对象实例。例如,一个菜单功能能够根据用户的“皮肤”首选项来决定是否采用水平的还是垂直的排
类中的面向对象编程封装应用逻辑。类,就是实例化的对象,每个单独的对象都有一个特定的身份和状态。单独的对象是一种组织代码的有用方法,但通常你会处理一组对象或者集合。
属性来自 SQL 查询的一组数据就是一个集合,就像本书前面章节介绍的 Monopoly 游戏示例的对象列表。
集合不一定是均一的。图形用户界面框架中的 Window 对象可以收集任意数量的控制对象 - Menu、Slider 和 Button。并且,集合的实现可以有多种方式:PHP 数字是一个集合,但也是一个散列表,一个链接列表,一个堆栈以及队列。
问题
如何操纵任意的对象集合?
解决方案
使用迭代器模式来提供对集合内容的统一存取。
你可能没有意识到这一点,但你每天都在使用迭代器模式 - 它潜藏在 PHP 的数组类型和各种数组操作函数中。(其实,给你一些固有类的数组的组合和一群用这些固有类工作的可变函数,你将不得不使用这些数组来处理对象集合。这是在 PHP 中的本地数组迭代:
$test = array(‘one’, ‘two’, ‘three’); $output = ‘’; reset($test); do { $output .= current($test); } while (next($test)); echo $output; // produces ‘onetwothree’ |
reset() 函数将迭代重新转到数组的开始;current() 返回当前元素的值;next() 则前进至数组中的下一个元素并返回新的 current() 值。当你超出数组的最后一个元素时,next() 返回 false。使用这些迭代方法,PHP 数组的内部实现就与你不相关了。迭代器结合了封装和多态的面向对象程序设计原理。使用迭代器,你可以对集合中的对象进行操作,而无需专门了解集合如何显现或者集合包含什么(对象的种类)。迭代器提供了不同固定迭代实现的统一接口,它完全包含了如何操纵特定集合的详细信息,包括显示哪些项(过滤)及其显示顺序(排序)。
让我们创建一个简单的对象,在数组中对它进行操作。(尽管该示例在 PHP5 环境下,但迭代器并不特定于 PHP5。虽然添加了较多的引用操作符,本章节中的大多数示例在 PHP4 下也能够运行)。对象 Lendable 表示诸如电影、相册等媒体,它作为 web 站点的一部分或服务,允许用户浏览或将他们的媒体集合分享给其他用户。(对 于该示例,请无需考虑其他方面。)让我们开始下面对 Lendable 基础设计的测试。
// PHP5 class LendableTestCase extends UnitTestCase { function TestCheckout() { $item = new Lendable; $this->assertFalse($item->borrower); $item->checkout(‘John’); $this->assertEqual(‘borrowed’, $item->status); $this->assertEqual(‘John’, $item->borrower); } function TestCheckin() { $item = new Lendable; $item->checkout(‘John’); $item->checkin(); $this->assertEqual(‘library’, $item->status); $this->assertFalse($item->borrower); } } |
要实现这一最初测试的需求,我们来创建一个带有若干公共属性和一些方法的类,
来触发这些属性的值:
class Lendable { public $status = ‘library’; public $borrower = ‘’; public function checkout($borrower) { $this->status = ‘borrowed’; $this->borrower = $borrower; } public function checkin() { $this->status = ‘library’; $this->borrower = ‘’; } } |
Lendable 是一个好的,普通的开端。让我们将它扩展到诸如 DVD 或 CD 的磁道项。媒体扩展了 Lendable,并且磁道详细记录了特定媒体的详细信息,包括项目的名称,发布的年份以及项本身的类型:
class Media extends Lendable { public $name; public $type; public $year; public function __construct($name, $year, $type=’dvd’ ) { $this->name = $name; $this->type = $type; $this->year = (int)$year; } } |
要使事情更加简单,媒体有三个公共的实例变量,Media::name,Media::year 和Media::type。构造函数采用了两个参数,将第一个存储在 $name 中,第二个存储在 $year 中。构造函数还允许可选的第三个参数来指定类型(缺省为dvd)。
给定单独的对象来操作,你现在可以创建一个容器来包含他们:Library。类似于常用的库,Library 应该能够添加,删除和计算集合中的项。甚至,Library 还应该允许访问集合(本章中的样本代码部分可看到示例)中的单一的项(对象)。
我们开始构建 Library 的测试用例。
class LibraryTestCase extends UnitTestCase { function TestCount() { $lib = new Library; $this->assertEqual(0, $lib->count()); } } |
它是满足这一测试的简单类:
class Library { function count() { return 0; } } |
继续将一些有趣的功能添加到测试中:
class LibraryTestCase extends UnitTestCase { function TestCount() { /* ... */ } function TestAdd() { $lib = new Library; $lib->add(‘one’); $this->assertEqual(1, $lib->count()); } } |
实现 add() 的简单方法是建立在 PHP 灵活数组函数的基础上:你可以将项添加到实例变量并使用 count() 来返回集合众项的数量。
class Library { protected $collection = array(); function count() { return count($this->collection); } function add($item) { $this->collection[] = $item; } } |
Library 现在是一个集合,但它没有提供检索或操纵单一数组成员的方法。
我们回到本章的重点,迭代器设计模式的实现。下列 UML 类图显示了 GoF 迭代器模式与 Media 和 Library 类结合使用巩固示例的方法。
分享:《PHP设计模式介绍》第六章 伪对象模式面向对象的编程之所以丰富多彩,部分是由于对象间的相互联系与作用。一个单一的对象就能封装一个复杂的子系统,使那些很复杂的操作能够通过一些方法的调用而简化。(无所不在的数据库连接就是这
- 相关链接:
- 教程说明:
PHP教程-《PHP设计模式介绍》第八章 迭代器模式。