《PHP设计模式介绍》第八章 迭代器模式
类中的面向对象编程封装应用逻辑类就是实例化的对象每个单独的对象都有一个特定的身份和状态单独的对象是一种组织代码的有用方法但通常你会处理一组对象或者集合
属性来自 SQL 查询的一组数据就是一个集合就像本书前面章节介绍的 Monopoly 游戏示例的对象列表
集合不一定是均一的图形用户界面框架中的 Window 对象可以收集任意数量的控制对象 - MenuSlider 和 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 数组的内部实现就与你不相关了迭代器结合了封装和多态的面向对象程序设计原理使用迭代器你可以对集合中的对象进行操作而无需专门了解集合如何显现或者集合包含什么(对象的种类)迭代器提供了不同固定迭代实现的统一接口它完全包含了如何操纵特定集合的详细信息包括显示哪些项(过滤)及其显示顺序(排序)
让我们创建一个简单的对象在数组中对它进行操作(尽管该示例在 PHP 环境下但迭代器并不特定于 PHP虽然添加了较多的引用操作符本章节中的大多数示例在 PHP 下也能够运行)对象 Lendable 表示诸如电影相册等媒体它作为 Web 站点的一部分或服务允许用户浏览或将他们的媒体集合分享给其他用户(对 于该示例请无需考虑其他方面)让我们开始下面对 Lendable 基础设计的测试
// PHP
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::nameMedia::year 和Media::type构造函数采用了两个参数将第一个存储在 $name 中第二个存储在 $year 中构造函数还允许可选的第三个参数来指定类型(缺省为dvd)
给定单独的对象来操作你现在可以创建一个容器来包含他们Library类似于常用的库Library 应该能够添加删除和计算集合中的项甚至Library 还应该允许访问集合(本章中的样本代码部分可看到示例)中的单一的项(对象)
我们开始构建 Library 的测试用例
class LibraryTestCase extends UnitTestCase {
function TestCount() {
$lib = new Library;
$this>assertEqual( $lib>count());
}
}
它是满足这一测试的简单类
class Library {
function count() {
return ;
}
}
继续将一些有趣的功能添加到测试中
class LibraryTestCase extends UnitTestCase {
function TestCount() { /* */ }
function TestAdd() {
$lib = new Library;
$lib>add(one);
$this>assertEqual( $lib>count());
}
}
实现 add() 的简单方法是建立在 PHP 灵活数组函数的基础上你可以将项添加到实例变量并使用 count() 来返回集合众项的数量
class Library {
protected $collection = array();
function count() {
return count($this>collection);
}
function add($item) {
$this>collection[] = $item;
}
}
Library 现在是一个集合但它没有提供检索或操纵单一数组成员的方法