第20章 迭代器模式
20.1 整理項目信息——苦差事
周五下午,我正在看技術網站,第六感官發覺有人在身后,扭頭一看,老大站在背后,我趕忙站起來。
“王經理,你找我?”
“哦,在看技術呀。有個事情找你談一下,你到我辦公室來一下。”
到老大辦公室還沒坐穩,老大就開始發話了。
“是這樣,剛剛我在看季報,我們每個項目的支出費用都很高,項目情況復雜,人員情況也不簡單,我看著也有點糊涂,你看,這是我們現在還在開發或者維護的103個項目,項目信息很亂,很多是兩年前的信息,你能不能先把這些項目最新情況重新打印一份給我,咱們好查查到底有什么問題。”老大說。
“這個好辦,我馬上去辦!”我爽快地答復道。
很快我設計了一個類圖,準備實施,如圖20-1所示。

圖20-1 項目信息類圖
簡單得不能再簡單的類圖,是個程序員都能實現。我們來看看這個簡單的東西,先看接口,如代碼清單20-1所示。
代碼清單20-1 項目信息接口
public?interface?IProject?{
?????//從老板這里看到的就是項目信息
?????public?String?getProjectInfo();
}
定義了一個接口,面向接口編程嘛,當然要定義接口了,然后看看實現類,如代碼清單20-2所示。
代碼清單20-2 項目信息的實現
public?class?Project?implements?IProject?{
?????//項目名稱
?????private?String?name?=?"";
?????//項目成員數量
?????private?int?num?=?0;
?????//項目費用
?????private?int?cost?=?0;
?????//定義一個構造函數,把所有老板需要看到的信息存儲起來
?????public?Project(String?name,int?num,int?cost){
?????????????//賦值到類的成員變量中
?????????????this.name?=?name;
?????????????this.num?=?num;
?????????????this.cost=cost;
?????}
?????//得到項目的信息
?????public?String?getProjectInfo()?{
?????????????String?info?=?"";
?????????????//獲得項目的名稱
?????????????info?=?info+?"項目名稱是:"?+?this.name;
?????????????//獲得項目人數
?????????????info?=?info?+?"\t項目人數:?"+?this.num;
?????????????//項目費用
?????????????info?=?info+?"\t?項目費用:"+?this.cost;
?????????????return?info;
?????}
}
實現類也是極度簡單,通過構造函數把要顯示的數據傳遞過來,然后放到getProjectInfo中顯示,這太容易了!然后我們老大要看看結果了,如代碼清單20-3所示。
代碼清單20-3 老大看報表的場景
public?class?Boss?{
?????????????public?static?void?main(String[]?args)?{
?????????????????????//定義一個List,存放所有的項目對象
?????????????????????ArrayList<IProject>?projectList?=?new?ArrayList<IProject>();
?????????????????????//增加星球大戰項目
?????????????????????projectList.add(new?Project("星球大戰項目",10,100000));
?????????????????????//增加扭轉時空項目
?????????????????????projectList.add(new?Project("扭轉時空項目",100,10000000));
?????????????????????//增加超人改造項目
?????????????????????projectList.add(new?Project("超人改造項目",10000,1000000000));
?????????????????????//這邊100個項目
?????????????????????for(int?i=4;i<104;i++){
?????????????????????????????projectList.add(new?Project("第"+i+"個項目",i*5,i*1000000));
?????????????????????}
?????????????????????//遍歷一下ArrayList,把所有的數據都取出
?????????????????????for(IProject?project:projectList){
?????????????System.out.println(project.getProjectInfo());
????????????????????????????????????????}
?????????????}
}
然后看一下我們的運行結果,如下所示:
項目名稱是:星球大戰項目 項目人數: 10 項目費用:100000
項目名稱是:扭轉時空項目 項目人數: 100 項目費用:10000000
項目名稱是:超人改造項目 項目人數: 10000 項目費用:1000000000
項目名稱是:第4個項目 項目人數: 20 項目費用:4000000
項目名稱是:第5個項目 項目人數: 25 項目費用:5000000
.
.
.
老大一看,非常開心,這么快就出結果了,大大地把我夸獎了一番,然后就去埋頭研究那堆枯燥的報表了。我回到座位上,又看了一遍程序(心里很樂,就又想看看自己的成果),想想(一日三省嘛),應該還有另外一種實現方式,因為是遍歷嘛,讓我想到的就是Java的迭代器接口java.util.iterator,它的作用就是遍歷Collection集合下的元素,那我們的程序還可以有另外一種實現,通過實現iterator接口來實現遍歷,先修正一下類圖,如圖20-2所示。

圖20-2 增加迭代接口的類圖
看著是不是復雜了很多?是的,是有點復雜了,是不是我們把簡單的事情復雜化了?請讀者繼續閱讀下去,我等會兒說明原因。我們先分析一下我們的類圖java.util.Iterator接口中聲明了三個方法,這是JDK定義的, ProjectIterator 實現該接口,并且聚合了Project對象,也就是把Project對象作為本對象的成員變量使用。看類圖還不是很清晰,我們一起看一下代碼,先看IProject接口的改變,如代碼清單20-4所示。
代碼清單20-4 項目信息接口
public?interface?IProject?{
?????//增加項目
?????public?void?add(String?name,int?num,int?cost);
?????//從老板這里看到的就是項目信息
?????public?String?getProjectInfo();
?????//獲得一個可以被遍歷的對象
?????public?IProjectIterator?iterator();
}
這里多了兩個方法,一個是add方法,這個方法是增加項目,也就是說產生了一個對象后,直接使用add方法增加項目信息。我們再來看其實現類,如代碼清單20-5所示。
代碼清單20-5 項目信息
public?class?Project?implements?IProject?{
?????//定義一個項目列表,說有的項目都放在這里
?????private?ArrayList<IProject>?projectList?=?new?ArrayList<IProject>();
?????//項目名稱
?????private?String?name?=?"";
?????//項目成員數量
?????private?int?num?=?0;
?????//項目費用
?????private?int?cost?=?0;
?????public?Project(){
?????
?????}
?????//定義一個構造函數,把所有老板需要看到的信息存儲起來
?????private?Project(String?name,int?num,int?cost){
?????????????//賦值到類的成員變量中
?????????????this.name?=?name;
?????????????this.num?=?num;
?????????????this.cost=cost;
?????}
?????//增加項目
?????public?void?add(String?name,int?num,int?cost){
?????????????this.projectList.add(new?Project(name,num,cost));
?????}
?????//得到項目的信息
?????public?String?getProjectInfo()?{
?????????????String?info?=?"";
?????????????//獲得項目的名稱
?????????????info?=?info+?"項目名稱是:"?+?this.name;
?????????????//獲得項目人數
?????????????info?=?info?+?"\t項目人數:?"+?this.num;
?????????????//項目費用
?????????????info?=?info+?"\t?項目費用:"+?this.cost;
?????????????return?info;
?????}
?????//產生一個遍歷對象
?????public?IProjectIterator?iterator(){
?????????????return?new?ProjectIterator(this.projectList);
?????}
}
通過構造函數,傳遞了一個項目所必需的信息,然后通過iterator()方法,把所有項目都返回到一個迭代器中。Iterator()方法看不懂不要緊,繼續向下閱讀。再看IProjectIterator接口,如代碼清單20-6所示。
代碼清單20-6 項目迭代器接口
public?interface?IProjectIterator?extends?Iterator?{
}
大家可能對該接口感覺很奇怪,你定義的這個接口方法、變量都沒有,有什么意義呢?有意義,所有的Java書上都會說要面向接口編程,你的接口是對一個事物的描述,也就是說我通過接口就知道這個事物有哪些方法,哪些屬性,我們這里的IProjectIterator是要建立一個指向Project類的迭代器,目前暫時定義的就是一個通用的迭代器,可能以后會增加IProjectIterator的一些屬性或者方法。當然了,你也可以在實現類上實現兩個接口,一個是Iterator,一個是IProjectIterator(這時候,這個接口就不用繼承Iterator),殺豬殺尾巴,各有各的殺法。我的習慣是:如果我要實現一個容器或者其他API提供接口時,我一般都自己先寫一個接口繼承,然后再繼承自己寫的接口,保證自己的實現類只用實現自己寫的接口(接口傳遞,當然也要實現頂層的接口),程序閱讀也清晰一些。我們繼續看迭代器的實現類,如代碼清單20-7所示。
代碼清單20-7 項目迭代器
public?class?ProjectIterator?implements?IProjectIterator?{
?????//所有的項目都放在ArrayList中
?????private?ArrayList<IProject>?projectList?=?new?ArrayList<IProject>();
?????private?int?currentItem?=?0;?
?????//構造函數傳入projectList
?????public?ProjectIterator(ArrayList<IProject>?projectList){
?????????????this.projectList?=?projectList;
?????}
?????//判斷是否還有元素,必須實現
?????public?boolean?hasNext()?{
?????????????//定義一個返回值
?????????????boolean?b?=?true;
?????????????if(this.currentItem>=projectList.size()||this.projectList.get(this.currentItem)==null){
??????????????????b?=false;
??????????}
?????????????return?b;
?????}
?????//取得下一個值
?????public?IProject?next()?{
?????????????return?(IProject)this.projectList.get(this.currentItem++);
?????}
?????//刪除一個對象
?????public?void?remove()?{
?????????????//暫時沒有使用到
?????}
}
細心的讀者可能會從代碼中發現一個問題,java.util.iterator接口中定義next()方法的返回值類型是E,而你在ProjectIterator中返回值卻是IProject,E和IProject有什么關系?
E是JDK 1.5中定義的新類型:元素(Element),是一個泛型符號,表示一個類型,具體什么類型是在實現或運行時決定,總之它代表的是一種類型,你在這個實現類中把它定義為ProjectIterator,在另外一個實現類可以把它定義為String,都沒有問題。它與Object這個類可是不同的,Object是所有類的父類,隨便一個類你都可以把它向上轉型到Object類,也只是因為它是所有類的父類,它才是一個通用類,而E是一個符號,代表所有的類,當然也代表Object了。
都寫完畢了,看看我們的Boss類有多少改動,如代碼清單20-8所示。
代碼清單20-8 老板看報表
public?class?Boss?{
?????????????public?static?void?main(String[]?args)?{
?????????????????????//定義一個List,存放所有的項目對象
?????????????????????IProject?project?=?new?Project();
?????????????????????//增加星球大戰項目
?????????????????????project.add("星球大戰項目ddddd",10,100000);
?????????????????????//增加扭轉時空項目
?????????????????????project.add("扭轉時空項目",100,10000000);
?????????????????????//增加超人改造項目
?????????????????????project.add("超人改造項目",10000,1000000000);
?????????????????????//這邊100個項目
?????????????????????for(int?i=4;i<104;i++){
?????????????????????????????project.add("第"+i+"個項目",i*5,i*1000000);
?????????????????????}
?????????????????????//遍歷一下ArrayList,把所有的數據都取出
?????????????????????IProjectIterator?projectIterator?=?project.iterator();
?????????????????????while(projectIterator.hasNext()){
?????????????????????????????IProject?p?=?(IProject)projectIterator.next();
?????????????????????????????System.out.println(p.getProjectInfo());
?????????????????????}
?????????????}
}
運行結果如下所示:
項目名稱是:星球大戰項目 項目人數: 10 項目費用:100000
項目名稱是:扭轉時空項目 項目人數: 100 項目費用:10000000
項目名稱是:超人改造項目 項目人數: 10000 項目費用:1000000000
項目名稱是:第4個項目 項目人數: 20 項目費用:4000000
項目名稱是:第5個項目 項目人數: 25 項目費用:5000000
.
.
.
運行結果完全相同,但是上面的程序復雜性增加了不少,難道我們退回到原始時代了嗎?非也,非也,只是我們回退到JDK 1.0.8版本的編程時代了,我們使用一種新的設計模式——迭代器模式。
- 前言
- 第一部分 大旗不揮,誰敢沖鋒——6大設計原則全新解讀
- 第1章 單一職責原則
- 1.2 絕殺技,打破你的傳統思維
- 1.3 我單純,所以我快樂
- 1.4 最佳實踐
- 第2章 里氏替換原則
- 2.2 糾紛不斷,規則壓制
- 2.3 最佳實踐
- 第3章 依賴倒置原則
- 3.2 言而無信,你太需要契約
- 3.3 依賴的三種寫法
- 3.4 最佳實踐
- 第4章 接口隔離原則
- 4.2 美女何其多,觀點各不同
- 4.3 保證接口的純潔性
- 4.4 最佳實踐
- 第5章 迪米特法則
- 5.2 我的知識你知道得越少越好
- 5.3 最佳實踐
- 第6章 開閉原則
- 6.2 開閉原則的廬山真面目
- 6.3 為什么要采用開閉原則
- 6.4 如何使用開閉原則
- 6.5 最佳實踐
- 第二部分 真刀實槍 ——23種設計模式完美演繹
- 第7章 單例模式
- 7.2 單例模式的定義
- 7.3 單例模式的應用
- 7.4 單例模式的擴展
- 7.5 最佳實踐
- 第8章 工廠方法模式
- 8.2 工廠方法模式的定義
- 8.3 工廠方法模式的應用
- 8.4 工廠方法模式的擴展
- 8.5 最佳實踐
- 第9章 抽象工廠模式
- 9.2 抽象工廠模式的定義
- 9.3 抽象工廠模式的應用
- 9.4 最佳實踐
- 第10章 模板方法模式
- 10.2 模板方法模式的定義
- 10.3 模板方法模式的應用
- 10.4 模板方法模式的擴展
- 10.5 最佳實踐
- 第11章 建造者模式
- 11.2 建造者模式的定義
- 11.3 建造者模式的應用
- 11.4 建造者模式的擴展
- 11.5 最佳實踐
- 第12章 代理模式
- 12.2 代理模式的定義
- 12.3 代理模式的應用
- 12.4 代理模式的擴展
- 12.5 最佳實踐
- 第13章 原型模式
- 13.2 原型模式的定義
- 13.3 原型模式的應用
- 13.4 原型模式的注意事項
- 13.5 最佳實踐
- 第14章 中介者模式
- 14.2 中介者模式的定義
- 14.3 中介者模式的應用
- 14.4 中介者模式的實際應用
- 14.5 最佳實踐
- 第15章 命令模式
- 15.2 命令模式的定義
- 15.3 命令模式的應用
- 15.4 命令模式的擴展
- 15.5 最佳實踐
- 第16章 責任鏈模式
- 16.2 責任鏈模式的定義
- 16.3 責任鏈模式的應用
- 16.4 最佳實踐
- 第17章 裝飾模式
- 17.2 裝飾模式的定義
- 17.3 裝飾模式應用
- 17.4 最佳實踐
- 第18章 策略模式
- 18.2 策略模式的定義
- 18.3 策略模式的應用
- 18.4 策略模式的擴展
- 18.5 最佳實踐
- 第19章 適配器模式
- 19.2 適配器模式的定義
- 19.3 適配器模式的應用
- 19.4 適配器模式的擴展
- 19.5 最佳實踐
- 第20章 迭代器模式
- 20.2 迭代器模式的定義
- 20.3 迭代器模式的應用
- 20.4 最佳實踐
- 第21章 組合模式
- 21.2 組合模式的定義
- 21.3 組合模式的應用
- 21.4 組合模式的擴展
- 21.5 最佳實踐
- 第22章 觀察者模式
- 22.2 觀察者模式的定義
- 22.3 觀察者模式的應用
- 22.4 觀察者模式的擴展
- 22.5 最佳實踐
- 第23章 門面模式
- 23.2 門面模式的定義
- 23.3 門面模式的應用
- 23.4 門面模式的注意事項
- 23.5 最佳實踐
- 第24章 備忘錄模式
- 24.2 備忘錄模式的定義
- 24.3 備忘錄模式的應用
- 24.4 備忘錄模式的擴展
- 24.5 最佳實踐
- 第25章 訪問者模式
- 25.2 訪問者模式的定義
- 25.3 訪問者模式的應用
- 25.4 訪問者模式的擴展
- 25.5 最佳實踐
- 第26章 狀態模式
- 26.2 狀態模式的定義
- 26.3 狀態模式的應用
- 第27章 解釋器模式
- 27.2 解釋器模式的定義
- 27.3 解釋器模式的應用
- 27.4 最佳實踐
- 第28章 享元模式
- 28.2 享元模式的定義
- 28.3 享元模式的應用
- 28.4 享元模式的擴展
- 28.5 最佳實踐
- 第29章 橋梁模式
- 29.2 橋梁模式的定義
- 29.3 橋梁模式的應用
- 29.4 最佳實踐
- 第三部分 誰的地盤誰做主 ——設計模式PK
- 第30章 創建類模式大PK
- 30.1 工廠方法模式VS建造者模式
- 30.2 抽象工廠模式VS建造者模式
- 第31章 結構類模式大PK
- 31.1 代理模式VS裝飾模式
- 31.2 裝飾模式VS適配器模式
- 第32章 行為類模式大PK
- 32.1 命令模式VS策略模式
- 32.2 策略模式VS狀態模式
- 32.3 觀察者模式VS責任鏈模式
- 第33章 跨戰區PK
- 33.1 策略模式VS橋梁模式
- 33.2 門面模式VS中介者模式
- 33.3 包裝模式群PK
- 第四部分 完美世界 ——設計模式混編
- 第34章 命令模式+責任鏈模式
- 34.2 混編小結
- 第35章 工廠方法模式+策略模式
- 35.2 混編小結
- 第36章 觀察者模式+中介者模式
- 36.2 混編小結
- 第五部分 擴展篇
- 第37章 MVC框架
- 37.2 最佳實踐
- 第38章 新模式
- 38.1 規格模式
- 38.2 對象池模式
- 38.3 雇工模式
- 38.4 黑板模式
- 38.5 空對象模式
- 附錄 23種設計模式彩圖