常常有一些組件在內部具有特定的數據結構,如果讓客戶程序依賴這些特定的數據結構,將極大地破壞組件的復用。這時候,將這些特定數據結構封裝在內部,在外部提供統一的接口,來實現與特定數據結構無關的訪問,是一種行之有效的解決方案。
典型模式
- Composite
- Iterator
- Chain of Resposibility
1.Composite模式(舉例android:View)
動機
在軟件某些情況下,客戶代碼過多地依賴于對象容器復雜的內部實現結構,對象容器內部實現結構(而非抽象接口)的變化將引起客戶代碼的頻繁變化,帶來了代碼的維護性、擴展性等弊端。
如何將“客戶代碼與復雜的對象容器結構”解耦?讓對象容器自己來實現自身的復雜結構,從而使得使得客戶代碼就像處理簡單對象一樣來處理復雜的對象容器?
模式定義
- 將對象組合成樹形結構以表示“部分整體”的層次結構。組合模式使得用戶對單個對象和使用具有一致性(穩定)。
結構
類圖
涉及角色
- 1.Component 是組合中的對象聲明接口,在適當的情況下,實現所有類共有接口的默認行為。聲明一個接口用于訪問和管理Component子部件。
- 2.Leaf 在組合中表示葉子結點對象,葉子結點沒有子結點。
- 3.Composite 定義有枝節點行為,用來存儲子部件,在Component接口中實現與子部件有關操作,如增加(add)和刪除(remove)等
要點總結
- Composite模式采用樹形結構來實現普遍存在的對象容器,從而將“一對多”的關系轉化為“一對一”的關系,使得客戶代碼可以一致地(復用)處理對象和對象容器,無需關心處理的是單個的對象,還是組合的對象容器。
- 將“客戶代碼與復雜的對象容器結構”解耦是Composite的核心思想,解耦之后,客戶代碼將與純粹的抽象接口——而非對象容器的內部實現結構——發生依賴,從而更能“應對變化”。
- Composite模式在具體實現中,可以讓父對象中的子對象反向追溯;如果父對性愛那個有頻繁的遍歷需求,可使用緩存技巧來改善效率。
2.Iterator迭代器
動機
- 在軟件構建過程中,集合對象內部結構常常變化各異。但對于這些集合對象,我們希望在不暴露其內部結構的同時,可以讓外部客戶代碼透明地訪問其中包含的元素;同時這種“透明遍歷”也為“同一種算法在多種集合對象上進行操作”提供了可能。
- 使用面向對象技術將這種遍歷機制抽象為“迭代器對象”為“應對變化中的集合對象”
提供了一種優雅的方式。
模式定義
- 提供一種方法順序訪問一個聚合對象中的各個元素,而又不暴露(穩定)該對象的內部表示。
結構
類圖
結構組成
- 抽象迭代器(Iterator): 定義遍歷元素所需要的方法,一般來說會有這么三個方法:取得第一個元素的方法first(),取得下一個元素的方法next(),判斷是否遍歷結束的方法isDone()(或者叫hasNext()),移出當前對象的方法remove(),
- 具體迭代器(ConcreteIterator): 就是抽象容器的具體實現類,比如List接口的有序列表實現ArrayList,List接口的鏈表實現LinkList,Set接口的哈希列表的實現HashSet等。
- 抽象聚合類(Aggregate): 一般是一個接口,提供一個iterator()方法,例如java中的Collection接口,List接口,Set接口等。
- 具體聚合類(ConcreteAggregate): 聚合實現創建相應迭代器的接口,該操作返回ConcreteIterator的一個適當的實例。
代碼實現
interface Iterator {
public Object next();
public boolean hasNext();
}
class ConcreteIterator implements Iterator{
private List list = new ArrayList();
private int cursor =0;
public ConcreteIterator(List list){
this.list = list;
}
public boolean hasNext() {
if(cursor==list.size()){
return false;
}
return true;
}
public Object next() {
Object obj = null;
if(this.hasNext()){
obj = this.list.get(cursor++);
}
return obj;
}
}
interface Aggregate {
public void add(Object obj);
public void remove(Object obj);
public Iterator iterator();
}
class ConcreteAggregate implements Aggregate {
private List list = new ArrayList();
public void add(Object obj) {
list.add(obj);
}
public Iterator iterator() {
return new ConcreteIterator(list);
}
public void remove(Object obj) {
list.remove(obj);
}
}
public class Client {
public static void main(String[] args){
Aggregate ag = new ConcreteAggregate();
ag.add("小明");
ag.add("小紅");
ag.add("小剛");
Iterator it = ag.iterator();
while(it.hasNext()){
String str = (String)it.next();
System.out.println(str);
}
}
}
要點總結
- 迭代抽象:訪問一個聚合對象的內容而無需暴露它的內部表示。
- 迭代多態:為遍歷不同的集合結構提供一個統一的接口,從而支持同樣的算法在不同的集合結構上進行操作。
- 迭代器的健壯性考慮:遍歷的同時更改迭代器所在的集合結構(add、remove)會導致問題(拋出異常)。