行为型模式
概述:
迭代器模式(Iterator):提供一种方法顺序一个聚合对象中各个元素,而又不暴露该对象内部表示。
实用场合:
1.访问一个聚合对象的内容而无需暴露它的内部表示。
2.支持对聚合对象的多种遍历。
3.为遍历不同的聚合结构提供一个统一的接口(即,多态迭代)。
类图:
代码结构示例:
1.迭代器抽象类
/// <summary>
/// 迭代器抽象类
/// 用于定义得到的开始对象,下一个对象,是否到结尾,当前对象方法,统一接口
/// </summary>
abstract class Iterator
{
public abstract object First();
public abstract object Next();
public abstract bool IsDone();
public abstract object CurrentItem();
}
2.实现迭代器类
class ConcreteIterator:Iterator
{
/// <summary>
/// 定义了一个具体聚集对象
/// </summary>
private ConcreteAggregate aggregate;
private int current = 0;
/// <summary>
/// 初始化对象将具体聚集类传入
/// </summary>
/// <param name="aggregate"></param>
public ConcreteIterator(ConcreteAggregate aggregate)
{
this.aggregate = aggregate;
}
/// <summary>
/// 第一个对象
/// </summary>
/// <returns></returns>
public override object First()
{
return aggregate[0];
}
/// <summary>
/// 得到聚集的下一对象
/// </summary>
/// <returns></returns>
public override object Next()
{
object ret = null;
current++;
if(current<aggregate.Count)
{
ret = aggregate[current];
}
return ret;
}
/// <summary>
/// 是否到结尾
/// </summary>
/// <returns></returns>
public override bool IsDone()
{
return current >= aggregate.Count ? true : false;
}
/// <summary>
/// 返回当前聚集对象
/// </summary>
/// <returns></returns>
public override object CurrentItem()
{
return aggregate[current];
}
}
3.聚集抽象类
/// <summary>
/// 聚集抽象类
/// </summary>
abstract class Aggregate
{
/// <summary>
/// 创建迭代器
/// </summary>
/// <returns></returns>
public abstract Iterator CreateIterator();
}
4.聚集实现类
class ConcreteAggregate:Aggregate
{
private IList<object> items = new List<object>();
public override Iterator CreateIterator()
{
return new ConcreteIterator(this);
}
/// <summary>
/// 返回聚集总个数
/// </summary>
public int Count
{
get { return items.Count; }
}
/// <summary>
/// 声明一个索引器
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
public object this[int index]
{
get { return items[index]; }
set { items.Insert(index, value); }
}
}
5.客户端实现
static void TestIterator()
{
//聚集对象
ConcreteAggregate a = new ConcreteAggregate();
a[0] = "张三";
a[1] = "李四";
a[2] = "叶鹏";
//声明迭代器对象
Iterator i = a.CreateIterator();
object item = i.First();
while(!i.IsDone())
{
Console.WriteLine("{0}回家吃饭",i.CurrentItem());
i.Next();
}
Console.Read();
}
一、sample 1
星际的任务关一般会有这样的设定:一开始电脑的农民不采矿,如果战斗打响,或者玩家造出第一个兵,电脑的农民开始采矿。
我们自然会想到把电脑的农民放到一个数组,然后一旦玩家造兵,或者战斗打响,把这个数组循环,让里面的农民采矿。
但问题出来了,由于每个任务的设定会有所不同,我们总希望任务的开发比较方便,而且容易修改(一旦发现bug)。
何况有些任务不是农民采矿,而是电脑出兵攻击玩家。
那么过多的固定细节(用数组存放)以及依赖细节(对数组循环),将使得代码的关联性变得很高。
待解决的问题:把循环处理的事务变的抽象。
思路:关键是对农民的循环,用数组处理只是一种方式,我们考虑抽象的数组,而不是具体的数组。
迭代器(Iterator)模式示例:
<?php
//聚集接口,意思是所有电脑的农民都聚集在这个类里面
interface IAggregate {
//让具体的聚集类实现的,获取使用的迭代器的方法
public function createIterator();
}
//具体的聚集类
class ConcreteAggregate implements IAggregate {
public $workers;//存放农民的数组,注意可以不用数组来处理,看完所有的代码就知道了
public function createIterator() {// 获取迭代器的方法
return new ConcreteIterator($this);
}
public function addElement($element) {//增加元素的方法,这里元素就是农民
$this->workers[] = $element;
}
public function getAt($index) {//获取元素的方法
return $this->workers[$index];
}
public function getLength() {// 获取元素的数量的方法
return count($this->workers);
}
}
//迭代器接口,注意php5有个内置的接口叫Iterator,所以这里我们改成IIterator
interface IIterator {
public function hasNext();//是否元素循环完毕
public function next(); //返回下一个元素,并将指针加1
}
//具体的迭代器类
class ConcreteIterator implements IIterator {
public $collection;//要迭代的集合
public $index;//指针
public function __construct(IAggregate $collection) {//构造函数,确定迭代的集合,并将指针置零
$this->collection = $collection;
$this->index = 0;
}
public function hasNext() {//是否元素循环完毕
if($this->index < $this->collection->getLength()) {
return true;
}
return false;
}
public function next() { //返回下一个元素,并将指针加1
$element = $this->collection->getAt($this->index);
$this->index++;
return $element;
}
}
//初始化电脑的农民的聚集对象
$farmerAggregate = new ConcreteAggregate();
// 添加农民,这里简单的用字符串表示
$farmerAggregate->addElement("SVC1");
$farmerAggregate->addElement("SVC2");
// 获取迭代器
$iterator = $farmerAggregate->createIterator();
//将农民聚集对象循环
while ($iterator->hasNext()) {
$element = $iterator->next();//获取下一个农民
echo $element; //我们简单的输出
}
?>
用途总结:迭代器模式建立了类似数组的形式,从上面的代码可以看到,如果要修改循环的处理,或者修改被循环的集合,都不必修改其它相关的代码。
实现总结:需要一个管理聚集的类,比如上面的 ConcreteAggregate。另外需要迭代器类,比如上面的ConcreteIterator。然后把所有的操作,比如添加元素,获取下一个元素,指针之类的数组方面的操作抽象出来,这样其它的代码只要使用方法,比如getLength(),而不是细节化的count()函数,这样即使不用数组存放农民,也不需要改动聚集类以外的代码。
二、sample 2
迭代器模式属于行为型模式,其意图是提供一种方法顺序访问一个聚合对象中得各个元素,而又不需要暴露该对象的内部表示。一个聚合对象,比如列表,应该提供一种方法来让别人可以访问他的元素。而又不需要暴露他的内部结构,此外,针对不同的需求,可能要以以下不同的方式遍历这个列表,但是即使可以预见所需要的那些遍历操作,你可能也不希望列表的接口中充斥着各种不同的遍历操作。有时还可能需要在同一个列表上同时进行多个遍历。迭代器模式可以帮助你解决所有这些问题。这一个模式的关键思想市将对列表的访问和遍历从列表对象中分离出来并放入一个迭代器对象中,迭代器类定义了一个访问该列表元素的接口,迭代器对象负责跟踪当前的元素,即他知道那些元素已经遍历过了。在实例化列表迭代器之前,必须提供待遍历的列表,一旦有了该列表迭代器的实例,就可以顺序访问该列表的各个元素。CurrentItem操作返回列表中得当前元素,First操作初始化迭代器,使当前元素指向列表的第一个元素,Next操作将当前元素指针向前推进一步,指向下一个元素,而IsDone检查是否已经越过最后一个元素,也就是完成了这次遍历。
例如常见的电视,可以定义一个 遥控器的,每个工厂生产的电视机都有配套的遥控器,这有点像抽象工厂模式,但是现在不是说抽象工厂模式,而说的重点是迭代器模式,电视的频道为Item,每个遥控器都会有遍历的功能,用以遍历所有的频道。如下图所示,
适用性:
l
访问一个聚合对象的内容而无需暴露他的内部表示。
l
支持对句和对象的多遍遍历。
l
为遍历不同的聚合结构提供一个统一的接口。
参与者:
Iterator:迭代器定义访问和遍历元素的接口。
ConcreteIterator(Controller):具体迭代器实现迭代器接口,对该聚合遍历时跟踪当前位置。
Aggregate(Televation):聚合定义了创建相应迭代器对象的接口。
ConcreteAggregate(HaierTV):具体聚合实现创建相应迭代器的接口,该操作返回ConcreteIterator的一个适当的实例。
协作关系:ConcreteIterator跟踪聚合中的当前对象,并能够计算出待遍历的后继对象。
使用迭代器的好处:
1.
他支持以不同的方式遍历一个聚合,复杂的聚合可用多种方式进行遍历。
2.
迭代器简化了聚合的接口有了迭代器的遍历接口,聚合本身就不需要类似的遍历接口了,这样就简化了聚合的接口。
3.
在同一个聚合上可以有多个遍历每个迭代器保持它自己的遍历状态。因此你可以同时进行多个遍历。
在本例子中,Television定义了一个返回各个频道列表的接口,这实际上是一个工厂方法,只是生产出来的产品所属的类型支持Iterator的操作。
具体的代码如下所示:
Iterator接口:
package iterator;
public interface Iterator{
public Item first();
public Item next();
public boolean isDone();
public Item currentItem();
}
Controller类实现了Iterator接口。
package iterator;
import java.util.Vector;
public class Controller implements Iterator{
private int current =0;
Vector channel;
public Controller(Vector v){
channel = v;
}
public Item first(){
current = 0;
return (Item)channel.get(current);
}
public Item next(){
current ++;
return (Item)channel.get(current);
}
public Item currentItem(){
return (Item)channel.get(current);
}
public boolean isDone(){
return current>= channel.size()-1;
}
}
Television接口:
package iterator;
import java.util.Vector;
public interface Television{
public Iterator createIterator();
public Vector getChannel();
}
HaierTV类实现了Television接口。
package iterator;
import java.util.Vector;
public class HaierTV implements Television{
private Vector channel;
public HaierTV(){
channel = new Vector();
channel.addElement(new Item("channel 1"));
channel.addElement(new Item("channel 2"));
channel.addElement(new Item("channel 3"));
channel.addElement(new Item("channel 4"));
channel.addElement(new Item("channel 5"));
channel.addElement(new Item("channel 6"));
channel.addElement(new Item("channel 7"));
}
public Vector getChannel(){
return channel;
}
public Iterator createIterator(){
return new Controller(channel);
}
}
Client客户端:
package iterator;
public class Client{
public static void main(String[] args){
Television tv = new HaierTV();
Iterator it =tv.createIterator();
System.out.println(it.first().getName());
while(!it.isDone()){
System.out.println(it.next().getName());
}
}
}
Item类的接口:
package iterator;
public class Item{
private String name;
public Item(String aName){
name = aName;
}
public String getName(){
return name;
}
}