設計模式--迭代器模式與組合方法模式
迭代器模式是將對物件的遍歷封裝成迭代器,對外部隱藏物件遍歷的具體實現。
而組合方法是實現對處於不同層次的同種物件提供一致性的遍歷方法。
首先我們開始討論迭代器模式。
我們在實踐過程中可以遇到這樣的情況,我們需要對用array,ArrayList,Stack 等模式包裝的一組物件進行遍歷
public class Item{
.........
}
public class Demo1{
Item[] items;
}
public class Demo2{
List<Item> items;
}
就如上面程式所示,我們需要堆Demo1 和Demo2的items 物件進行遍歷操作,1種很常見的方式是對Demo1和Demo2的物件的型別提供不同的遍歷方式。
for(int i = 0 ; i < demo1.items.length;i++){.....}
for(int i = 0 ; i < demo2.items.size();i++){.....}
(先無視這裡違反的最小知識原則) 這樣的實現是明顯有問題,如果我們存在額外的物件型別比如生活stack ,那麼我們仍然需要重新按照這種方法修改源程式,如果我們存在多個不同型別的物件,我們需要按照物件的型別對他們進行分類然後對他們分別進行遍歷,這樣的實現,一方面存在很多冗餘程式碼,另外一方面違反開閉原則。
迭代器模式針對這樣的情況提供了這樣的實現方式。
public class Item{ ......... } public interface GetItemIterator{ public Iterator creatIterator(); } public class ArrayIterator implements Iterator{ ..... } public class Demo1 implements GetItemIterator{ Item[] items; public Iterator creatIterator(){ return new ArrayIterator(items); } } public class Demo2 implements GetItemIterator{ List<Item> items; public Iterator creatIterator(){ return items.Iterator();} }
我們對於每一個需要提供物件遍歷的類實現一個建立迭代器的方法,在主程式中 我們對具體物件的遍歷可以通過迭代器實現,在主程式中對對個Demo1 Demo2物件訪問的程式碼也可以合併,去除了冗餘的程式碼。
使用迭代器模式最大的好處就是對外部隱藏了內部物件遍歷的具體實現, 如果所有遍歷都通過迭代器遍歷,那麼可以消除遍歷物件時產生的冗餘程式碼。
接下來讓我們討論組合方法模式。
組合方法讓我想起了之前在作業系統課中實現對檔案目錄系統訪問的程式。
檔案目錄是通過樹的方式實現,目錄區的每條記錄可以被稱作目錄項,如果目錄項指向檔案,那麼目錄項中的存的跳轉地址就是檔案頭的地址,如果目錄項是一個目錄,那麼他的跳轉地址指向的區域是一個需要被當做目錄區訪問的空間。
我當初給出的實現方法是順序讀入根目錄下的目錄項,遇到檔案,直接出棧檔名和檔案地址,遇到目錄,輸出目錄名,然後用遞迴讀取該目錄指向的目錄區的目錄內容。
這個也是組合方法的一個實現方法。
組合方法的目的是使客戶用一致的方法去處理物件和子物件
組合方法存在這樣的關係, 其中Leaf 指的是標準葉節點,在檔案系統中對應的就是檔案,而Compoiste可以包含0個或多個其他的Composite和0個或多個Leaf,在檔案系統中對應的就是目錄,在Component是兩者的統一介面,在檔案系統中對應的是目錄項,注意兩者的作用不同,目錄項是為了標誌型別,而component是提供統一實現的介面,簡單說就是一個Component使得程式與具體實現類解耦。
下面是程式碼
public abstract class CatalogueItem{
public String getItemName throws Exception{ throw new Exception("不支援");}
public String getItemLocation throws Exception{ throw new Exception("不支援");}
public Iterator getSubItems throws Exception{ throw new Exception("不支援");}
}
public class Catalogue extends CatalogueItem{
public String getItemName throws Exception{ return name;}
public String getItemLocation throws Exception{return location;}
public Iterator getSubItems throws Exception{ return new ItemIterator(items)}
}
public class FileItem extends CatalogueItem{
public String getItemName throws Exception{ return name;}
public String getItemLocation throws Exception{return location;}
public Iterator getSubItems throws Exception{ return new NullIterator();}
}
//空迭代器
public class NullIterator implements Iterator{
public boolean hasNext() {
return false;
}
public Object next() {
return null;
}
public void remove() {
System.out.println("不支援remove操作");}
}
//普通迭代器
public class ItemIterator implements Iterator {
Stack stack = new Stack<Iterator>();
public ItemIterator(Iterator params) { stack.push(params); }
public boolean hasNext() {
if (stack.size() > 0) {
Iterator temp = (Iterator) stack.peek();
if (temp.hasNext()) {
return true;
}
else {
stack.pop();
return hasNext();
}
} else { return false; }
}
public Object next() {
Item reval = (Item) ((Iterator) stack.peek()).next();
try {
stack.push(reval.getSubItems());
} catch (Exception e) { }
return reval;
}
public void remove() {
System.out.println("不支援remove操作");
}
}
組合模式下 類對外提供了同一的迭代器介面,而隱藏了內在的層次性結構, 這樣的實現與我之前用的那種方法的區別在於是否使用instanceof來判定類別並給與不同的操作。
組合模式的問題在於提供統一的介面,於是某些不需要的方法被一些類繼承了,我們基本是使用異常的方式處理掉,另外由於層次性結構被隱藏了,所以我們不能對目錄進行縮排顯示。
instanceof 方法的好處是可以使用遞迴的方法提供更加細緻的處理,但是違反了開閉的原則,如果出現修改需求,instanceof帶來的修改負擔很大