Java設計模式——迭代器模式
迭代器模式的定義是:
提供一種方法順序訪問一個聚合物件中的各個元素,而又不暴露其內部表示
問題:
這裡引用《Head First》中的一個示例,如果一個聚合物件(選單)中存在兩種不同的儲存結構(ArrayList & Array),該如何操作?
如果是簡單的逐個遍歷,程式的擴充套件性就會很差, 如果再增加新的儲存結構,就需要對程式碼進行大量的修改
解決辦法:
可以建立一個物件,將他稱之為迭代器(Iterator),利用它來封裝“遍歷集合內每個物件的過程”,然後迭代器暗中根據容器的不同,使用不同的呼叫方法。
(這裡可以這麼理解,用迭代器去迭代,可以都呼叫next 和hasNext方法,然後在這兩個方法中寫具體的實現,這樣我們如果要是需要新增儲存結構的話,也只需要呼叫這兩個方法,然後在對應的迭代器中去書寫相應的迭代程式碼就可以了)
這裡先介紹一下Java中的迭代器,Java中的迭代器位於java.util.Iterator包下,是一個輕量級的物件,建立代價小,主要方法有
1 hashNext (判斷當前元素是否存在(不會移動指標)
2 next(返回當前元素,並指向下一個元素)
使用迭代器的好處:
1 提供了一種簡單的遍歷方式
2 支援以不同的方式去遍歷一個聚合物件(ArrayList和Array的遍歷方式不同,但是使用迭代器可以遍歷這兩種儲存結構組成的聚合物件)
3 不會暴露內部實現細節
4 解耦合
5 具有擴充套件性,增加新的聚合類和迭代器都很方便,無需修改原有程式碼
例子程式碼實現:
Menu,提供通用的方法規範:
package spring.design.pattern.iterator;
import java.util.Iterator;
/**
* Description:
*
* @author 慕容藍
* @version 1.0
* @date 2018/11/27 17:09
*/
public interface Menu {
Iterator createIterator();
}
選單(陣列),在這個類裡,它會把資料儲存的資料,交給迭代器進行處理
package spring.design.pattern.iterator;
import java.util.Iterator;
/**
* Description:晚餐類.
*
* @author 慕容藍
* @version 1.0
* @date 2018/11/27 15:05
*/
public class DinerMenu implements Menu{
static final int Max_ITEMS = 6;
int numberOfItems = 0;
MenuItem[] menuItems;
public DinerMenu() {
menuItems = new MenuItem[Max_ITEMS];
AddItem("紅燒肉", "Braised pork", false, 10.5);
AddItem("番茄炒蛋", "Tomato scrambled eggs", false, 8.5);
}
public void AddItem(String name, String description, Boolean vegetarian, double price) {
MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
if (numberOfItems > Max_ITEMS) {
throw new RuntimeException("選單已滿");
} else {
menuItems[numberOfItems] = menuItem;
numberOfItems++;
}
}
@Override
public Iterator createIterator(){
return new DinerMenuIterator(menuItems);
}
}
選單(集合),同上
package spring.design.pattern.iterator;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Iterator;
/**
* Description:早餐類.
*
* @author 慕容藍
* @version 1.0
* @date 2018/11/27 14:59
*/
public class PancakeHouseMenu implements Menu{
ArrayList<MenuItem> menuItems;
public PancakeHouseMenu() {
menuItems = new ArrayList();
AddItem("牛奶", "milk", false, 3.0);
AddItem("麵包", "bread", false, 1.0);
}
public void AddItem(String name, String description, Boolean vegetarian, double price) {
MenuItem menuItem = new MenuItem(name, description, vegetarian, price);
menuItems.add(menuItem);
}
@Override
public Iterator createIterator() {
return menuItems.iterator();
}
}
陣列&集合中儲存的物件:
package spring.design.pattern.iterator;
/**
* Description:選單類.
*
* @author 慕容藍
* @version 1.0
* @date 2018/11/27 14:55
*/
public class MenuItem {
private String name;
private String description;
private boolean vegetarin;
private double price;
public MenuItem(String name, String description, boolean vegetarin, double price) {
this.name = name;
this.description = description;
this.vegetarin = vegetarin;
this.price = price;
}
public double getPrice() {
return price;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public boolean isVegetarin() {
return vegetarin;
}
}
陣列的迭代器,這裡重寫了迭代器的三個方法hasNext next remove:
package spring.design.pattern.iterator;
import java.util.Iterator;
/**
* Description:晚餐選單迭代器.
*
* @author 慕容藍
* @version 1.0
* @date 2018/11/27 15:23
*/
public class DinerMenuIterator implements Iterator {
/** position記錄當前陣列遍歷的位置 */
int position = 0;
MenuItem[] items;
public DinerMenuIterator(MenuItem[] items) {
this.items = items;
}
@Override
public boolean hasNext() {
if (position >= items.length || items[position] == null) {
return false;
}
return true;
}
@Override
public Object next() {
MenuItem menuItem = items[position];
position = position + 1;
return menuItem;
}
@Override
public void remove() {
if (position <= 0) {
throw new IllegalStateException("You can't remove an item you've done at least one next()");
}
if (items[position - 1] != null) {
for (int i = position - 1; i < (items.length - 1); i++) {
items[i] = items[i + 1];
}
items[items.length - 1] = null;
}
}
}
服務員類,負責列印資料:
package spring.design.pattern.iterator;
import java.util.Iterator;
/**
* Description:服務員類.
*
* @author muronglan
* @version 1.0
* @date 2018/11/27 15:30
*/
public class Waitress {
/** init() */
Menu pancakeHouseMenu ;
Menu dinerMenu ;
public Waitress(Menu pancakeHouseMenu, Menu dinerMenu) {
this.pancakeHouseMenu = pancakeHouseMenu;
this.dinerMenu = dinerMenu;
}
public void printMenu() {
Iterator pancakeIterator = pancakeHouseMenu.createIterator();
Iterator dinerIterator = dinerMenu.createIterator();
System.out.println("MENU\n --- \nBREAKFAST");
printMenu(pancakeIterator);
System.out.println("\nLUNCH");
printMenu(dinerIterator);
}
public void printMenu(Iterator iterator) {
while (iterator.hasNext()) {
MenuItem menuItem = (MenuItem) iterator.next();
System.out.println(menuItem.getName() + ",");
System.out.println(menuItem.getPrice() + " --- ");
System.out.println(menuItem.getDescription());
}
}
}
測試類,負責展現效果:
package spring.design.pattern.iterator;
/**
* Description:測試類.
*
* @author 慕容藍
* @version 1.0
* @date 2018/11/27 16:04
*/
public class Test {
public static void main(String[] args) {
PancakeHouseMenu pancakeHouseMenu = new PancakeHouseMenu();
DinerMenu dinerMenu = new DinerMenu();
Waitress waitress = new Waitress(pancakeHouseMenu,dinerMenu);
waitress.printMenu();
}
}
找時間補上一張UML圖
在Java程式碼中的集合中,也是使用到了迭代器
Collection介面,繼承了Iteratable介面,該介面中的Iterator方法可以產生一個
Iterator物件:
public interface Collection<E> extends Iterable<E> {…}
/**
* Performs the given action for each element of the {@code Iterable}
* until all elements have been processed or the action throws an
* exception. Unless otherwise specified by the implementing class,
* actions are performed in the order of iteration (if an iteration order
* is specified). Exceptions thrown by the action are relayed to the
* caller.
*
* @implSpec
* <p>The default implementation behaves as if:
* <pre>{@code
* for (T t : this)
* action.accept(t);
* }</pre>
*
* @param action The action to be performed for each element
* @throws NullPointerException if the specified action is null
* @since 1.8
*/
大概意思是對{@code Iterable} 的每個元素執行給定操作,如果產生了異常,異常會被拋給呼叫者
然後使用Iterator就可以對Conllection中的元素進行迭代操作:
public interface Iterator<E> {
/**
* 判斷當前元素是否存在(不會移動指標)
*/
boolean hasNext();
/**
* 返回當前元素,並指向下一個元素
*/
E next();
…
}
我們可以通過增強型for迴圈去完成集合中的迭代,也可以自己去呼叫iterator方法,建立一個迭代器
package spring;
import java.util.ArrayList;
import java.util.List;
/**
* Description:
*
* @author 慕容藍
* @version 1.0
* @date 2018/11/27 11:52
*/
public class Test {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
for (Integer i : list) {
System.out.print(i);
}
}
}
package spring;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* Description:
*
* @author 慕容藍
* @version 1.0
* @date 2018/11/27 11:52
*/
public class Test {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
}