Java 设计模式之迭代器模式
一、了解迭代器模式
1.1 什么是迭代器模式
迭代器模式提供一種方法順序訪問一個(gè)聚合對象中的各個(gè)元素,而又不暴露其內(nèi)部的表示。
迭代器模式把游走的任務(wù)放在迭代器上,而不是聚合上。這樣簡化了聚合的接口和實(shí)現(xiàn),也可以讓責(zé)任各得其所。
1.2 迭代器模式組成結(jié)構(gòu)
- 迭代器(Iterator):迭代器定義訪問和遍歷元素的接口。
- 具體迭代器(ConcreteIterator):具體迭代器實(shí)現(xiàn)迭代器接口,對該聚合遍歷時(shí)跟蹤當(dāng)前位置。
- 聚合(Aggregate):聚合定義創(chuàng)建相應(yīng)迭代器對象的接口。
- 具體聚合(ConcreteAggregate):具體聚合實(shí)現(xiàn)創(chuàng)建相應(yīng)迭代器的接口,該操作返回 ConcreteIterator 的一個(gè)適當(dāng)?shù)膶?shí)例。
1.3 迭代器模式 UML 圖解
1.4 迭代器模式適用場景
- 訪問一個(gè)聚合對象的內(nèi)容而無需暴露它的內(nèi)部表示。
- 支持對聚合對象的多種遍歷。
- 為遍歷不同的聚合結(jié)構(gòu)提供一個(gè)統(tǒng)一的接口。
二、迭代器模式具體應(yīng)用
2.1 問題描述
包子店與沙縣小吃合并啦:有一家包子店,他們負(fù)責(zé)提供早餐,賣各式各樣的包子,并提供豆?jié){之類的飲品;也有一家沙縣小吃,它們負(fù)責(zé)提供午餐和晚餐,賣一些蓋澆飯和煲仔飯。為了獲得更多的盈利,后來這兩家店合并了。
但是卻發(fā)現(xiàn)了一個(gè)問題,原來的包子店提供的菜單是用 List 集合結(jié)合存儲的,而沙縣小吃的菜單卻是由數(shù)組存儲的。所以在提供菜單的時(shí)候就會很麻煩,需要使用兩個(gè)不同的循環(huán)來遍歷對應(yīng)的集合和數(shù)組,才能打印完整的菜單 (當(dāng)然這項(xiàng)工作是由服務(wù)員完成的)。有沒有更好的解決辦法呢?這時(shí)候迭代器模式就登場了。
現(xiàn)在我們將這個(gè)問題用到代碼中去實(shí)現(xiàn)。
2.2 迭代器模式問題設(shè)計(jì)
2.3 代碼實(shí)現(xiàn)
菜單信息封裝 MenuItem 類
package com.jas.iterator;/*** 用來封裝菜單食物信息*/ public class MenuItem {String name; //食物名字double price; //食物價(jià)格public MenuItem(String name, double price){this.name = name;this.price = price;}public String getName() {return name;}public double getPrice() {return price;} }聚合 Menu 接口
package com.jas.iterator;import java.util.Iterator;public interface Menu {Iterator<MenuItem> createIterator(); }具體聚合 BZMenu 類
package com.jas.iterator;import java.util.ArrayList; import java.util.Iterator; import java.util.List;/*** 包子菜單類,實(shí)現(xiàn)了 Menu 接口中的 createIterator() 方法*/ public class BZMenu implements Menu{List<MenuItem> menuItems;/*** 通過構(gòu)造函數(shù),在菜單里添加一些菜品*/public BZMenu() {menuItems = new ArrayList<>();addItem("雪菜包",1.0);addItem("灌湯包",1.0);addItem("韭菜包",1.0);addItem("豬肉包",1.0);}public void addItem(String name, double price){MenuItem menuItem = new MenuItem(name, price);menuItems.add(menuItem);}/*** 返回包子菜單信息的迭代器* * @return*/@Overridepublic Iterator<MenuItem> createIterator() {return new BZMenuIterator(menuItems);} }具體聚合 SXMenu 類
package com.jas.iterator;import java.util.Iterator;/*** 沙縣菜單類,實(shí)現(xiàn)了 Menu 接口中的 createIterator() 方法*/ public class SXMenu implements Menu{static final int MAX_ITEMS = 4;int indexOfItems = 0;MenuItem[] menuItems;/*** 通過構(gòu)造函數(shù),在菜單里添加一些菜品*/public SXMenu(){menuItems = new MenuItem[MAX_ITEMS];addItem("青椒肉絲蓋澆飯",10.0);addItem("西紅柿雞蛋蓋澆飯",10.0);addItem("牛肉土豆煲仔飯",15.0);addItem("金針菇煲仔飯",10.0);}public void addItem(String name, double price){MenuItem menuItem = new MenuItem(name, price);if(indexOfItems >= MAX_ITEMS){System.out.println("菜單已滿!");}else {menuItems[indexOfItems] = menuItem;indexOfItems ++;}}/*** 返回沙縣菜單信息的迭代器* * @return*/@Overridepublic Iterator<MenuItem> createIterator() {return new SXMenuIterator(menuItems);} }具體迭代器 BZMenuIterator 類
package com.jas.iterator;import java.util.Iterator; import java.util.List;/*** 包子菜單信息迭代器*/ public class BZMenuIterator implements Iterator {List<MenuItem> menuItems;int position = 0;/*** 通過構(gòu)造函數(shù),實(shí)例化存儲包子信息的菜單 List 集合* 雖然可以直接使用 Iterator 來遍歷集合,為了更好理解迭代器模式,這里自己手寫一個(gè)迭代器* * @param menuItems*/public BZMenuIterator(List<MenuItem> menuItems){this.menuItems = menuItems;}@Overridepublic boolean hasNext() {if(position >= menuItems.size() || menuItems.get(position) == null){return false;}else {return true;}}@Overridepublic Object next() {MenuItem menuItem = menuItems.get(position);position += 1;return menuItem;} }具體迭代器 BZMenuIterator 類
package com.jas.iterator;import java.util.Iterator;/*** 沙縣菜單迭代器*/ public class SXMenuIterator implements Iterator {MenuItem[] menuItems;int position = 0;/*** 通過構(gòu)造函數(shù)實(shí)例化存儲沙縣信息的菜單數(shù)組* * @param menuItems*/public SXMenuIterator(MenuItem[] menuItems){this.menuItems = menuItems;}@Overridepublic boolean hasNext() {if(position >= menuItems.length || menuItems[position] == null){return false;}else {return true;}}@Overridepublic Object next() {MenuItem menuItem = menuItems[position];position += 1;return menuItem;} }Waitress 類
package com.jas.iterator;import java.util.Iterator;public class Waitress {BZMenu bzMenu;SXMenu sxMenu;public Waitress(BZMenu bzMenu, SXMenu sxMenu){this.bzMenu = bzMenu;this.sxMenu = sxMenu;}public void printMenu(){Iterator<MenuItem> iterator = bzMenu.createIterator();Iterator<MenuItem> iterator1 = sxMenu.createIterator();System.out.println("包子菜單為:");printMenu(iterator);System.out.println("沙縣菜單為:");printMenu(iterator1);}private void printMenu(Iterator iterator){while (iterator.hasNext()){MenuItem menuItem = (MenuItem) iterator.next();System.out.print(menuItem.getName() + ": ");System.out.println(menuItem.getPrice());}} }測試類
package com.jas.iterator;public class MenuTestDrive {public static void main(String[] args) {BZMenu bzMenu = new BZMenu();SXMenu sxMenu = new SXMenu();Waitress waitress = new Waitress(bzMenu,sxMenu);waitress.printMenu();} }/*** 輸出* 包子菜單為:* 雪菜包: 1.0* 灌湯包: 1.0* 韭菜包: 1.0* 豬肉包: 1.0* 沙縣菜單為:* 青椒肉絲蓋澆飯: 10.0* 西紅柿雞蛋蓋澆飯: 10.0* 牛肉土豆煲仔飯: 15.0* 金針菇煲仔飯: 10.0*/2.4 問題總結(jié)
為了解決打印菜單的難題,我們新建了兩個(gè)具體迭代器,分別用于遍歷存儲包子菜單的集合和存儲沙縣菜單的數(shù)組,在包子菜單和沙縣菜單的類中提供外部可調(diào)用的遍歷菜單的迭代器。這樣一來,我們把遍歷菜單的任務(wù)放在了具體迭代器類中,而不是具體聚合類中。外部不用知道其內(nèi)部菜單是如何存儲的,你只需要給外部提供一個(gè)迭代器對象,就能完成遍歷菜單的任務(wù) 。
三、 迭代器模式總結(jié)
3.1 迭代器模式優(yōu)缺點(diǎn)總結(jié)
優(yōu)點(diǎn)
- 它支持以不同的方式遍歷一個(gè)聚合對象。
- 迭代器簡化了聚合類。
- 在同一個(gè)聚合上可以有多個(gè)遍歷。
- 在迭代器模式中,增加新的聚合類和迭代器類都很方便,無須修改原有代碼。
缺點(diǎn)
對于比較簡單的遍歷(像數(shù)組或者有序列表),使用迭代器方式遍歷較為繁瑣。
3.2 迭代器模式知識點(diǎn)總結(jié)
- 迭代器允許訪問聚合的元素,而不需要暴露它的內(nèi)部結(jié)構(gòu)。
- 迭代器將遍歷集合的任務(wù)封裝進(jìn)一個(gè)對象中。
- 使用迭代器的時(shí)候,我們依賴聚合提供遍歷。
- 迭代器提供了一個(gè)通用的接口 (可以自定義也可以使用 Java API 內(nèi)置的),讓我們遍歷聚合的項(xiàng),當(dāng)我們編碼使用聚合的項(xiàng)時(shí),可以考慮使用多態(tài)機(jī)制。
PS:點(diǎn)擊了解更多設(shè)計(jì)模式 http://blog.csdn.net/codejas/article/details/79236013
參考文獻(xiàn)
《Head First 設(shè)計(jì)模式》
總結(jié)
以上是生活随笔為你收集整理的Java 设计模式之迭代器模式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java 设计模式之模板方法模式
- 下一篇: 厨房打印机一菜一单怎么设置?