Java學習記錄--適配器模式
標簽(空格分隔): java
適配器模式是一種比較簡單的設計模式,該博文從Java的Set集合入手,分析適配器模式適用場景,解決的問題,導致的缺點等.希望對你有幫助.
適配器模式,可以這樣解釋,用現(xiàn)有的組件去匹配實現(xiàn)要求提供的功能.舉個例子:對于Java的HashSet集合,實際上是由一個HashMap映射來實現(xiàn)的,那么就可以理解為用現(xiàn)有的HashMap組件去實現(xiàn)了要求沒有重復的Set集合這一功能.那么,這就是適配器模式,對于HashSet來說,更詳細的叫法是對象適配器模式.
1.對象適配器模式
舉個例子,MAC新款用的是雷電3接口,但是以前都是USB接口,那么就需要一個轉換器,提供USB到雷電3的數據傳輸轉換,那么在HashSet實現(xiàn)中每一個類都承擔什么角色呢?
首先看HashSet的部分源碼:
//被適配的HashMap
private transient HashMap<E,Object> map;
//作為Map值的元素
private static final Object PRESENT = new Object();
//初始化被適配的HashMap
public HashSet() {
map = new HashMap<>();
}
那么對于HashMap來說,HashMap就是USB接口,Set這個interface是新款的雷電3接口,于是HashSet就成了這個轉換器,所提供的功能是把HashMap中的key單獨表現(xiàn)為一個集合.
再看HashSet提供的轉換:
public int size() {
return map.size();
}
public boolean contains(Object o) {
return map.containsKey(o);
}
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
public boolean remove(Object o) {
return map.remove(o)==PRESENT;
}
就像插口適配器提供數據傳輸轉換一樣,HashSet提供對HashMap映射的轉換.這樣來看的話很容易理解.參考下圖:

2.類適配器
如果把HashSet改造成下面這種形式的話,那就是類適配器,顯然這種方式很不靈活,繼承導致方法的混亂沖突,調用的不清晰等.因此建議使用對象適配器.
public class HashSet<K> extends HashMap<K,Object> implements Set<K> {
private static final Object PRESENT = new Object();
@Override
public boolean add(K k) {
return super.put(k, PRESENT) == null;
}
@Override
public boolean remove(Object key) {
return super.remove(key) == PRESENT;
}
}
3.總結
3.1適用情景
- 系統(tǒng)需要使用現(xiàn)有的類,而這些類的接口不符合系統(tǒng)的接口。
- 想要建立一個可以重用的類,用于與一些彼此之間沒有太大關聯(lián)的一些類,包括一些可能在將來引進的類一起工作。
- 兩個類所做的事情相同或相似,但是具有不同接口的時候。
- 舊的系統(tǒng)開發(fā)的類已經實現(xiàn)了一些功能,但是客戶端卻只能以另外接口的形式訪問,但我們不希望手動更改原有類的時候。
- 使用第三方組件,組件接口定義和自己定義的不同,不希望修改自己的接口,但是要使用第三方組件接口的功能。
3.2 優(yōu)點
- 通過適配器,客戶端可以調用同一接口,因而對客戶端來說是透明的。這樣做更簡單、更直接、更緊湊。
- 復用了現(xiàn)存的類,解決了現(xiàn)存類和復用環(huán)境要求不一致的問題。
- 將目標類和適配者類解耦,通過引入一個適配器類重用現(xiàn)有的適配者類,而無需修改原有代碼.
- 一個對象適配器可以把多個不同的適配者類適配到同一個目標,也就是說,同一個適配器可以把適配者類和它的子類都適配到目標接口。
3.3缺點
- 對象適配器造成代碼耦合,如果被適配的類,如HashMap由較為大的改動可能會影響適配器.另外更換適配器比較麻煩.
- 對于類適配器,不夠靈活,寫的不得當造成代碼混亂.
根據自己的業(yè)務選擇最適合的方式即可.
4.補充
4.1和裝飾者模式比較
適配器像是轉換器,使用新接口來調用原接口,并且有時候需要轉換下功能,不應該對外直接暴露被適配的類的功能,而是通過自己本身的方法提供.如下面方法:
public boolean contains(Object o) {
return map.containsKey(o);
}
裝飾者模式是提供新的職責,并且原封不動的提供被裝飾者功能.
適配器是知道被適配者的詳細情況的(就是那個類或那個接口)。裝飾者只知道其接口是什么,至于其具體類型(是基類還是其他派生類)只有在運行期間才知道。
兩者的有一個共同的名稱叫做'包裝模式',兩者的最主要的區(qū)別在于使用目的不同,其他則大致思想一致.
參考博文:
http://blog.csdn.net/jason0539/article/details/22468457