1. 程式人生 > >Java設計模式——迭代器模式

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());
   }
 }
}