簡介
迭代器模式(Iterator Pattern),是一種結構型設計模式。給資料物件構建一套按順序訪問集合物件元素的方式,而不需要知道資料物件的底層表示。
迭代器模式是與集合共存的,我們只要實現一個集合,就需要同時提供這個集合的迭代器,就像Java中的Collection,List、Set、Map等,這些集合都有自己的迭代器。假如我們要實現一個這樣的新的容器,就可以引入迭代器模式,給我們的容器實現一個迭代器。
作用
- 可以提供多種遍歷物件的方式,把元素之間查詢呼叫的責任交給迭代器,而不是聚合物件。
- 分離了集合物件的遍歷行為,抽象出一個迭代器類來負責,這樣既可以做到不暴露集合的內部結構,又可讓外部程式碼透明地訪問集合內部的資料。
實現步驟
- 建立迭代器介面,定義hasNext()和next()方法
- 建立資料容器介面,用來建立迭代器
- 建立具體資料列表,實現資料容器介面,可以建立迭代器,內含資料列表物件
- 建立某種資料物件的迭代器,實現hasNext()以及next()方法,並且關聯上資料物件列表
UML
Java程式碼
迭代器抽象介面
// Iterator.java 迭代器抽象介面,提供next和hasNext方法 public interface Iterator { public boolean hasNext(); public Object next(); }
具體迭代器
// ObjectIterator.java 物件迭代器,實現了抽象迭代器的方法,聚合了物件列表 public class ObjectIterator implements Iterator { private ObjectList objectList; int index; public ObjectIterator(ObjectList objectList) { this.objectList = objectList; } @Override public boolean hasNext() { if (index < objectList.size()) { return true; } return false; } @Override public Object next() { if (this.hasNext()) { // 返回資料物件提供的get方法,每訪問一次則增加下標 return objectList.get(index++); } return null; } }
資料容器介面
// Container.go 建立抽象容器介面,建立一個迭代器 public interface Container { public Iterator createIterator(); }
具體資料物件
// ObjectList.java 物件列表,是一種資料容器,可以建立一個迭代器 public class ObjectList implements Container { private Object[] objects = { "Google", "Apple", "Amazon" }; @Override public Iterator createIterator() { System.out.println(this.getClass().getName() + "::createIterator() [獲取迭代器 ObjectIterator]"); // 把當前物件傳給迭代器 return new ObjectIterator(this); } public void setObjects(Object[] objects) { this.objects = objects; } public int size() { return objects.length; } public Object get(int index) { return objects[index]; } }
測試呼叫
/* * 迭代器模式是給資料容器建立單獨的迭代器,用來遍歷裡面的資料物件 * 資料容器和迭代器相互關聯,外部透過迭代器來訪問資料容器 * 透過這種方式由迭代器類來負責資料遍歷,這樣可以做到不暴露集合的內部結構 */ int i = 0; ObjectList objectList = new ObjectList(); objectList.setObjects(new String[] { "Thomas", "Merry", "Jack", "Tony", "Jerry", "Joey" }); // for迴圈迭代物件 for (Iterator iter = objectList.createIterator(); iter.hasNext();) { String name = (String) iter.next(); System.out.println("objectList[" + i + "] = " + name); i++; } // while迴圈迭代物件 Iterator iter2 = objectList.createIterator(); objectList.setObjects(new Integer[] { 3, 5, 7, 9, 11 }); while (iter2.hasNext()) { System.out.println(iter2.next()); }
Go程式碼
迭代器抽象介面
// Iterator.go 迭代器抽象介面,提供next和hasNext方法 type Iterator interface { HasNext() bool Next() string }
具體迭代器
// ObjectIterator.go 物件迭代器,實現了抽象迭代器的方法,聚合了物件列表 type ObjectIterator struct { // 迭代器索引 index int // 聚合了資料物件 objectList *ObjectList } func (o *ObjectIterator) HasNext() bool { if o.index < o.objectList.Size() { return true } return false } func (o *ObjectIterator) Next() string { if o.HasNext() { // 返回資料物件提供的get方法,每訪問一次下標增加1位 item := o.objectList.Get(o.index) o.index += 1 return item } return "" }
資料容器介面
// Container.go 建立抽象容器介面,建立一個迭代器 type Container interface { CreateIterator() Iterator }
具體資料物件
// ObjectList.go 物件列表,是一種資料容器,可以建立一個迭代器 type ObjectList struct { // 內部的資料結構 objects []string } func (o *ObjectList) CreateIterator() Iterator { fmt.Println("ObjectList::CreateIterator() [獲取迭代器 ObjectIterator]") // 建立迭代器例項,繫結新建當前物件 return &ObjectIterator{ objectList: o, } } func (o *ObjectList) SetObjects(objects []string) { o.objects = objects } func (o *ObjectList) GetObjects() []string { return o.objects } func (o *ObjectList) Size() int { return len(o.objects) } func (o *ObjectList) Get(index int) string { return o.objects[index] }
測試呼叫
/* * 迭代器模式是給資料容器建立單獨的迭代器,用來遍歷裡面的資料物件 * 資料容器和迭代器相互關聯,外部透過迭代器來訪問資料容器 * 透過這種方式由迭代器類來負責資料遍歷,這樣可以做到不暴露集合的內部結構 */ int i = 0; ObjectList objectList = new ObjectList(); objectList.setObjects(new String[] { "Thomas", "Merry", "Jack", "Tony", "Jerry", "Joey" }); // for迴圈迭代物件 for (Iterator iter = objectList.createIterator(); iter.hasNext();) { String name = (String) iter.next(); System.out.println("objectList[" + i + "] = " + name); i++; } // while迴圈迭代物件 Iterator iter2 = objectList.createIterator(); objectList.setObjects(new Integer[] { 3, 5, 7, 9, 11 }); while (iter2.hasNext()) { System.out.println(iter2.next()); }
C語言簡版
#include <stdio.h> #include <stdlib.h> // 簡單版C語言迭代器模式,自己構建List資料型別 // 資料結構,這裡使用連結串列作為示例 struct List { char *data; struct List *next; }; // 迭代器結構體 struct Iterator { struct List *current; int (*has_next)(struct Iterator *); // 判斷是否還有下一個元素 char *(*next)(struct Iterator *, char **); // 獲取下一個元素 }; // 判斷是否還有下一個元素 int has_next(struct Iterator *iter) { return iter->current != NULL; } // 獲取下一個元素 char *next(struct Iterator *iter, char **value) { if (iter->current == NULL) { return NULL; } *value = iter->current->data; iter->current = iter->current->next; return *value; } // 初始化迭代器 void create_iterator(struct Iterator *iter, struct List *head) { iter->current = head; iter->has_next = &has_next; iter->next = &next; } // 遍歷連結串列 void iterate_list(struct List *head) { struct Iterator iter; char *value; create_iterator(&iter, head); while (iter.has_next(&iter)) { iter.next(&iter, &value); printf("\r\n %s ", value); } printf("\n"); } int main() { printf("test start:\r\n"); // 構造一個連結串列 struct List *head = (struct List *)malloc(sizeof(struct List)); head->data = "Tom"; head->next = (struct List *)malloc(sizeof(struct List)); head->next->data = "Jerry"; head->next->next = (struct List *)malloc(sizeof(struct List)); head->next->next->data = "Max"; head->next->next->next = NULL; // 使用迭代器遍歷連結串列 iterate_list(head); // 釋放連結串列記憶體 while (head != NULL) { struct List *temp = head; head = head->next; free(temp); } return 0; }
更多語言版本
不同語言實現設計模式:https://github.com/microwind/design-pattern