行為型模式
概述:
迭代器模式(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,所以這裡我們改成IIteratorinterface 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定義了一個返回各個頻道列表的介面,這實際上是一個Factory 方法,只是生產出來的產品所屬的類型支援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; }}