適配器模式,有時候也成爲包裝樣式或者包裝 (wrapper)。將一個類的接口轉接成用戶所期待的,使得因接口不兼容而不能在一塊兒工做的類能夠在一塊兒工做。 — wikipediahtml
適配器模式屬於結構型模式。這一類型的模式主要是爲了解決如何組織現有的類,設計他們的交互方式,從而達到必定的目的。包括了外觀模式、代理模式、裝飾模式、橋接模式、組合模式、享元模式以及今天要說的適配器模式。java
那麼問題來了,適配器模式究竟是爲了解決什麼問題呢?編程
在軟件開發領域,咱們常常面臨的一個問題就是你須要把一個方形的木頭楔進一個圓形的洞裏面!這個問題在現實生活中可能除了『削它』以外沒別的什麼好辦法,不過軟件世界中,由於是『軟的』,咱們能夠很是方便的進行各類改造來知足咱們的需求。數組
如上圖所示,經過在 Client 和 Service 兩個對象之間加入一個 Adapter 對象,兩個原本沒法在一塊兒工做的類如今能夠合做了。從這個圖也很容易看出來,adapter 的其實就是在 client 和 service 之間建立了一箇中間層,這又應驗了一句老話『計算機科學領域的任何問題均可以經過增長一個間接的中間層來解決』。app
Adapter 模式的概念很是容易理解,在現實世界中咱們也很容易找到相似概念的東西。dom
好比咱們在作演示的時候常常須要使用一個視頻數據線來鏈接筆記本和投影儀。從筆記本的角度看(做爲 client),它只能經過 usb-c 向外輸出視頻信號,但咱們的投影儀(做爲 service)的接口是固定的,只接受 HDMI 的信號,沒法更改(更改爲本比較高)。一個 usb-c to HDMI 的數據線就起到了 adapter 的做用。編程語言
相似的還有不少,好比手機的充電器,蘋果的雷電口轉 3.5mm 耳機口轉換器,好比咱們出國旅行都須要帶的插頭轉換器,三通閥門,等等。ide
根據適配器的實現方式,能夠分對象適配器和類適配器兩個類型。ui
對象適配器使用了對象組合的方式,adapter 實現一個類的接口,並內部容納了另一個類對象。spa
類適配器使用了多繼承的方式。 adapter 同時從兩個對象類繼承,因此這種方式一般在支持多繼承的編程語言出現,好比 C++。
在這種模式下,adapter 不須要 wrap service 對象了,由於它經過繼承,既是 client 又是 sercie,在 client 調用的方法中直接調用本身繼承的 service 方法就能夠了。
Java 由於不支持多繼承,一般沒法實現這種模式,但也能夠實現相似的形式:讓 adapter 來繼承 Service 類並實現 Client Interface。與多繼承的差異就是 adapter 仍是須要本身來實現 client 接口定義的方法。
整體來講,建議使用對象適配器的方式。
咱們來找一個實際的例子來看看適配器到底應該怎麼用。
在 Java 標準庫中,Arrays.asList() 就實現了適配器模式。
/** * Returns a fixed-size list backed by the specified array. (Changes to * the returned list "write through" to the array.) This method acts * as bridge between array-based and collection-based APIs, in * combination with {@link Collection#toArray}. ... */
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
複製代碼
這個方法接受變長參數的元素,返回了一個 ArrayList 對象,此 ArrayList 非彼 ArrayList,它是在 Arrays 類的一個 private 內部類,充當的是適配器的角色。
private static class ArrayList<E> extends AbstractList<E> implements RandomAccess, java.io.Serializable {
private final E[] a;
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
@Override
public int size() {
return a.length;
}
...
複製代碼
這個適配器類的會將 List 接口方法的調用代理給內部的數組對象。這個適配器類主要做用是爲了協調以數組爲基礎的 API 和以集合爲基礎的 API。在這個例子中,service 就是數組,client interface 就是 List,而依賴 List 的 API 就是 client。
優點 適配器也是一種包裝模式,還有委託的意思在裏面,它適合在系統後期擴展、修改時候使用,由於只是新引入的 adapter 類,不須要對 client 和 service 作任何修改,很是的靈活。 適配器模式也符合 SOLID 中的單一職責原則和開閉原則。前者主要體如今它將接口轉換的工做從 client 分離出來,由適配器來承擔;後者主要體如今適配器不須要 client 和 service 作任何的改動,而是經過繼承來實現須要的功能。
劣勢 有得必有失。靈活性的增長一般也意味着複雜度的增長。 由於引入了新的類,應用的總體複雜度增長了。若是不加限制的過分使用適配器,會讓系統變的很是混亂,所以若是條件容許的話,也許更好的方案是直接對系統進行重構。
@monkeyM