設計模式15—設計模式之迭代器模式(Iterator)(行為型)

來源:互聯網
上載者:User
1.情境類比

一個公司收購了另一個公司,現在需要整合兩個公司之間的工資資料。但是兩個公司,一個是用鏈表格儲存體的,一個是用數組儲存的,但是工資的資料模型差不多。
上述問題可以抽象為:如何能夠以一個統一的方式來訪問內部實現不同的彙總對象。
2.使用迭代器模式來解決2.1迭代器定義

提供一種方法順序訪問一個彙總對象中的各個元素,而又不需要暴露該對象的內部表示。
2.2迭代器的結構

 
2.3迭代器範例程式碼

package demo13.iterator.example1;/** * 迭代器介面,定義訪問和遍曆元素的操作 */public interface Iterator {/** * 移動到彙總對象的第一個位置 */public void first();/** * 移動到彙總對象的下一個位置 */public void next();/** * 判斷是否已經移動彙總對象的最後一個位置 * @return true表示已經移動到彙總對象的最後一個位置, *         false表示還沒有移動到彙總對象的最後一個位置 */public boolean isDone();/** * 擷取迭代的當前元素 * @return 迭代的當前元素 */public Object currentItem();}***********************************************************************package demo13.iterator.example1;/** * 具體迭代器實現對象,示意的是彙總對象為數組的迭代器 * 不同的彙總對象相應的迭代器實現是不一樣的 */public class ConcreteIterator implements Iterator {/** * 持有被迭代的具體的彙總對象 */private ConcreteAggregate aggregate;/** * 內部索引,記錄當前迭代到的索引位置。 * -1表示剛開始的時候,迭代器指向彙總對象第一個對象之前 */private int index = -1;/** * 構造方法,傳入被迭代的具體的彙總對象 * @param aggregate 被迭代的具體的彙總對象 */public ConcreteIterator(ConcreteAggregate aggregate) {this.aggregate = aggregate;}public void first(){index = 0;}public void next(){if(index < this.aggregate.size()){index = index + 1;}}public boolean isDone(){if(index == this.aggregate.size()){return true;}return false;}public Object currentItem(){return this.aggregate.get(index);}}***********************************************************************package demo13.iterator.example1;/** * 彙總對象的介面,定義建立相應迭代器對象的介面 */public abstract class Aggregate {/** * Factory 方法,建立相應迭代器對象的介面 * @return 相應迭代器對象的介面 */public abstract Iterator createIterator();}**********************************************************************package demo13.iterator.example1;/** * 具體的彙總對象,實現建立相應迭代器對象的功能 */public class ConcreteAggregate extends Aggregate {/** * 示意,表示彙總對象具體的內容 */private String[] ss = null;/** * 構造方法,傳入彙總對象具體的內容 * @param ss 彙總對象具體的內容 */public ConcreteAggregate(String[] ss){this.ss = ss;}public Iterator createIterator() {//實現建立Iterator的Factory 方法return new ConcreteIterator(this);}/** * 擷取索引所對應的元素 * @param index 索引 * @return 索引所對應的元素 */public Object get(int index){Object retObj = null;if(index < ss.length){retObj = ss[index];}return retObj;}/** * 擷取彙總對象的大小 * @return 彙總對象的大小 */public int size(){return this.ss.length;}}**********************************************************************package demo13.iterator.example1;public class Client {/** * 示意方法,使用迭代器的功能。 * 這裡示意使用迭代器來迭代彙總對象 */public void someOperation(){String[] names = {"張三","李四","王五"};//建立彙總對象Aggregate aggregate = new ConcreteAggregate(names);//迴圈輸出彙總對象中的值Iterator it = aggregate.createIterator();//首先設定迭代器到第一個元素it.first();while(!it.isDone()){//取出當前的元素來Object obj = it.currentItem();System.out.println("the obj=="+obj);//如果還沒有迭代到最後,那麼就向下迭代一個it.next();}}public static void main(String[] args) {//可以簡單的測試一下Client client = new Client();client.someOperation();}}
3.不使用迭代器來實現執行個體(情境類比)代碼

代碼很簡單,注釋的很清楚,就不一一贅述了。

package demo13.iterator.example2;/** * 工資描述模型對象 */public class PayModel {/** * 支付工資的人員 */private String userName;/** * 支付的工資數額 */private double pay;public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public double getPay() {return pay;}public void setPay(double pay) {this.pay = pay;}public String toString(){return "userName="+userName+",pay="+pay;}}*****************************************************************package demo13.iterator.example2;import java.util.*;/** * 客戶方已有的工資管理對象 */public class PayManager{/** * 彙總對象,這裡是Java的集合對象 */private List list = new ArrayList();/** * 擷取工資列表 * @return 工資列表 */public List getPayList(){return list;}/** * 計算工資,其實應該有很多參數,為了示範從簡 */public void calcPay(){//計算工資,並把工資資訊填充到工資列表裡面//為了測試,做點假資料進去PayModel pm1 = new PayModel();pm1.setPay(3800);pm1.setUserName("張三");PayModel pm2 = new PayModel();pm2.setPay(5800);pm2.setUserName("李四");list.add(pm1);list.add(pm2);}}**********************************************************************package demo13.iterator.example2;/** * 被客戶方收購的那個公司的工資管理類 */public class SalaryManager{/** * 用數組管理 */private PayModel[] pms = null;/** * 擷取工資列表 * @return 工資列表 */public PayModel[] getPays(){return pms;}/** * 計算工資,其實應該有很多參數,為了示範從簡 */public void calcSalary(){//計算工資,並把工資資訊填充到工資列表裡面//為了測試,做點假資料進去PayModel pm1 = new PayModel();pm1.setPay(2200);pm1.setUserName("王五");PayModel pm2 = new PayModel();pm2.setPay(3600);pm2.setUserName("趙六");pms = new PayModel[2];pms[0] = pm1;pms[1] = pm2;}}***********************************************************************************************package demo13.iterator.example2;import java.util.*;public class Client {public static void main(String[] args) {//訪問集團的工資列表PayManager payManager= new PayManager();//先計算再擷取payManager.calcPay();Collection payList = payManager.getPayList();Iterator it = payList.iterator();System.out.println("集團工資列表:");while(it.hasNext()){PayModel pm = (PayModel)it.next();System.out.println(pm);}//訪問新收購公司的工資列表SalaryManager salaryManager = new SalaryManager();//先計算再擷取salaryManager.calcSalary();PayModel[] pms = salaryManager.getPays();System.out.println("新收購的公司工資列表:");for(int i=0;i<pms.length;i++){System.out.println(pms[i]);}}}
4.使用迭代器模式來實現情境模式

通過剛才的代碼,大家很清楚的發現,用戶端使用的結構是不一樣的,一個是數組,一個是集合,這樣就知道了其內部的表現形式。那麼我們能不能使用迭代器模式改成如下這個樣子呢?

public class Client {public static void main(String[] args) {//訪問集團的工資列表PayManager payManager= new PayManager();//先計算再擷取payManager.calcPay();System.out.println("集團工資列表:");test(payManager.createIterator());//訪問新收購公司的工資列表SalaryManager salaryManager = new SalaryManager();//先計算再擷取salaryManager.calcSalary();System.out.println("新收購的公司工資列表:");test(salaryManager.createIterator());}/** * 測試通過訪問彙總對象的迭代器,是否能正常訪問彙總對象 * @param it 彙總對象的迭代器 */private static void test(Iterator it){//迴圈輸出彙總對象中的值//首先設定迭代器到第一個元素it.first();while(!it.isDone()){//取出當前的元素來Object obj = it.currentItem();System.out.println("the obj=="+obj);//如果還沒有迭代到最後,那麼就向下迭代一個it.next();}}}

這樣用戶端使用起來是相當舒服的,答案是可以實現的,下面我們就來統一訪問彙總的介面。
代碼如下:
4.1為了讓用戶端能夠統一進行訪問,最容易的方式就是為它們定義一個統一的介面

package demo13.iterator.example3;/** * 迭代器介面,定義訪問和遍曆元素的操作 */public interface Iterator {/** * 移動到彙總對象的第一個位置 */public void first();/** * 移動到彙總對象的下一個位置 */public void next();/** * 判斷是否已經移動彙總對象的最後一個位置 * @return true表示已經移動彙總對象的最後一個位置, *         false表示還沒有移動到彙總對象的最後一個位置 */public boolean isDone();/** * 擷取迭代的當前元素 * @return 迭代的當前元素 */public Object currentItem();}
4.2兩個具體的實現介面類,一個是數組,一個是集合

這兩個類基本上是一樣的,所以實際上可以用一個類來替換也是沒有問題的。

package demo13.iterator.example3;/** * 用來實現訪問數組的迭代介面 */public class ArrayIteratorImpl implements Iterator{/** * 用來存放被迭代的彙總對象 */private SalaryManager aggregate = null;/** * 用來記錄當前迭代到的位置索引 * -1表示剛開始的時候,迭代器指向彙總對象第一個對象之前 */private int index = -1;public ArrayIteratorImpl(SalaryManager aggregate){this.aggregate = aggregate;}public void first(){index = 0;}public void next(){if(index < this.aggregate.size()){index = index + 1;}}public boolean isDone(){if(index == this.aggregate.size()){return true;}return false;}public Object currentItem(){return this.aggregate.get(index);}}**********************************************************************************************package demo13.iterator.example3;/** * 用來實現訪問Collection集合的迭代介面,為了外部統一訪問方式 */public class CollectionIteratorImpl implements Iterator {/** * 用來存放被迭代的彙總對象 */private PayManager aggregate = null;/** * 用來記錄當前迭代到的位置索引 -1表示剛開始的時候,迭代器指向彙總對象第一個對象之前 */private int index = -1;public CollectionIteratorImpl(PayManager aggregate) {this.aggregate = aggregate;}public void first() {index = 0;}public void next() {if (index < this.aggregate.size()) {index = index + 1;}}public boolean isDone() {if (index == this.aggregate.size()) {return true;}return false;}public Object currentItem() {return this.aggregate.get(index);}}
4.3定義一個擷取訪問彙總的介面
package demo13.iterator.example3;/** * 彙總對象的介面,定義建立相應迭代器對象的介面 */public abstract class Aggregate {/** * Factory 方法,建立相應迭代器對象的介面 * @return 相應迭代器對象的介面 */public abstract Iterator createIterator();}
4.4分別修改PayManager和SalaryManager類

加了一個構造方法,更改了get方法還有size方法

package demo13.iterator.example3;import java.util.*;/** * 客戶方已有的工資管理對象 */public class PayManager extends Aggregate{/** * 彙總對象,這裡是Java的集合對象 */private List list = new ArrayList();/** * 擷取工資列表 * @return 工資列表 */public List getPayList(){return list;}/** * 計算工資,其實應該有很多參數,為了示範從簡 */public void calcPay(){//計算工資,並把工資資訊填充到工資列表裡面//為了測試,做點假資料進去PayModel pm1 = new PayModel();pm1.setPay(3800);pm1.setUserName("張三");PayModel pm2 = new PayModel();pm2.setPay(5800);pm2.setUserName("李四");list.add(pm1);list.add(pm2);}public Iterator createIterator(){return new CollectionIteratorImpl(this);}public Object get(int index){Object retObj = null;if(index < this.list.size()){retObj = this.list.get(index);}return retObj;}public int size(){return this.list.size();}}*********************************************************************package demo13.iterator.example3;/** * 被客戶方收購的那個公司的工資管理類 */public class SalaryManager extends Aggregate {/** * 用數組管理 */private PayModel[] pms = null;/** * 擷取工資列表 *  * @return 工資列表 */public PayModel[] getPays() {return pms;}/** * 計算工資,其實應該有很多參數,為了示範從簡 */public void calcSalary() {// 計算工資,並把工資資訊填充到工資列表裡面// 為了測試,做點假資料進去PayModel pm1 = new PayModel();pm1.setPay(2200);pm1.setUserName("王五");PayModel pm2 = new PayModel();pm2.setPay(3600);pm2.setUserName("趙六");pms = new PayModel[2];pms[0] = pm1;pms[1] = pm2;}public Iterator createIterator() {return new ArrayIteratorImpl(this);}public Object get(int index) {Object retObj = null;if (index < pms.length) {retObj = pms[index];}return retObj;}public int size() {return this.pms.length;}}
4.5用戶端如下
package demo13.iterator.example3;import java.util.*;public class Client {public static void main(String[] args) {//訪問集團的工資列表PayManager payManager= new PayManager();//先計算再擷取payManager.calcPay();System.out.println("集團工資列表:");test(payManager.createIterator());//訪問新收購公司的工資列表SalaryManager salaryManager = new SalaryManager();//先計算再擷取salaryManager.calcSalary();System.out.println("新收購的公司工資列表:");test(salaryManager.createIterator());}/** * 測試通過訪問彙總對象的迭代器,是否能正常訪問彙總對象 * @param it 彙總對象的迭代器 */private static void test(Iterator it){//迴圈輸出彙總對象中的值//首先設定迭代器到第一個元素it.first();while(!it.isDone()){//取出當前的元素來Object obj = it.currentItem();System.out.println("the obj=="+obj);//如果還沒有迭代到最後,那麼就向下迭代一個it.next();}}}
4.6代碼結構圖

看到圖就一目瞭然了
 
5.迭代器模式講解5.1要點

以不同的方式遍曆彙總對象
多態迭代:通過一個迭代介面可以訪問不同的彙總結構。
關鍵思想:把對彙總對象的遍曆和訪問從彙總對象中分離出來,放入單獨的迭代器中。
5.2迭代器模式優點

更好的封裝性
簡化了彙總的介面
可以以不同的遍曆方式來遍曆一個彙總
5.3迭代器模式本質

控制訪問彙總對象中的元素

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.