適配器模式(Adapter)是23種設計模式之一。DP中是這麼定義外觀模式的:java
適配器模式將一個類的接口轉換成客戶但願的另一個接口。Adapter模式使得本來因爲接口不兼容而不能在一塊兒工做的那些類能夠在一塊兒工做。git
咱們生活中就常用到適配器,適配器這個詞最先應該是出如今電工學裏。有些國家用110V電壓,而我國使用的是220V電壓,但咱們的電器,例如手機、筆記本電腦、平板電腦等,是不能什麼電壓都能用的,因而咱們就須要使用電源適配器,這樣一來只要是電,無論多少伏都能適配成須要的電壓。而適配器模式就是起到這種做用,將既有的,可是不可以直接使用的,也沒法進行改造的,經過適配後,讓它可以被使用。設計模式
在軟件開發中,也就是系統的數據和行爲都正確,可是接口不符時,咱們應該考慮用適配器,目的是使控制範圍以外的一個原有對象與某個接口匹配。適配器模式主要應用於但願複用一些現存的類,可是接口又與複用環境要求不一致的狀況,好比在須要對早期代碼複用一些功能等應用上頗有實際價值。bash
在GoF的設計模式中,對適配器模式講了兩種類型,類適配器模式和對象適配器模式,因爲類適配器模式是經過多重繼承對一個接口與另外一個接口進行匹配,而Java語言不支持多繼承,因此這裏只介紹對象適配器模式。ide
適配器模式(Adapter)結構圖:設計
使用簡單的代碼來實現這個模式的結構:code
Target類:對象
package org.zero01.target; /** * 客戶所指望的接口 */ public class Target { public void request() { System.out.println("普通請求!"); } }
Adaptee類:blog
package org.zero01.adapter; /** * 須要適配的類 */ public class Adaptee { public void specificRequest() { System.out.println("特殊請求!"); } }
Adapter類:繼承
package org.zero01.adapter; import org.zero01.target.Target; /** * 適配器類 */ public class Adapter extends Target { private Adaptee adaptee = new Adaptee(); // 把request方法的調用轉換成specificRequest方法的調用 public void request() { adaptee.specificRequest(); } }
客戶端:
package org.zero01.client; import org.zero01.adapter.Adapter; import org.zero01.target.Target; public class Client { public static void main(String[] args) { Target target=new Adapter(); // 客戶端調用target的request方法便可 target.request(); } }
何時適合用適配器模式:
1.想使用一個已經存在的類,可是它的接口,也就是方法與你要求的不一樣時能夠考慮使用適配器模式。也就是說兩個類所作的事情類似或相同,可是具備不一樣的接口時可使用適配器模式。使用了適配器模式後,類之間就會共享同一個接口,使得客戶端代碼只須要統一調用同一個接口便可,這樣可使客戶端的代碼更簡單、直接、緊湊。
2.軟件開發後期或維護期適合使用適配器模式,由於維護時會因爲開發人員的不一樣,而形成功能相似,但接口不一樣的狀況,此時就適合使用適配器模式。
3.設計一個系統時,若是使用了第三方的組件,而這個組件的接口與咱們本身的系統接口不一樣,可是咱們又沒有必要爲了迎合它而改動本身的接口,這種狀況也能夠考慮使用適配器模式來解決接口不一樣的問題。
何時不適合用適配器模式:
在設計初期時,就應該統一好接口的定義,儘可能不要把接口設計成不一樣的,以及須要規範好類與方法的命名,因此在這種開發前期的狀況下,若是出現接口不一樣,應該是將不一樣的接口重構成統一的接口,而不是考慮使用適配器模式。適配器模式應該用在雙方都不太容易修改接口的時候再使用適配器模式進行適配。
因此咱們開發時應該事先預防接口的不一樣的問題,這樣不匹配的問題就不會發生。在有小的接口不統一而引發問題時,應該及時對接口進行重構,這樣問題不至於擴大。只有碰到沒法改變原有的設計和代碼的狀況時,才考慮適配。過後控制不如事中控制,事中控制不如事前控制。適配器模式雖好,可是若是無視它的應用場合而盲目使用,就是本末倒置了。
簡單的適配器模式示例:
我這裏以前寫了一個數碼產品充電的系統,可是我如今想要加入一個小燈泡,可是小燈泡與數碼產品實現的方法不同,可是它們一樣須要使用電,因此這時候就可使用適配器了。
結構圖以下:
數碼產品接口,定義一個充電方法:
package org.zero01.target; public interface DigitalProducts { public void charge(); }
手機、平板以及筆記本電腦都實現了這個接口:
public class Phone implements DigitalProducts{ public void charge() { System.out.println("手機使用4v電壓充電"); } } public class IPad implements DigitalProducts{ public void charge() { System.out.println("平板使用6v電壓充電"); } } public class MacBook implements DigitalProducts{ public void charge() { System.out.println("筆記本電腦使用14v電壓充電"); } }
我如今要加入一個小燈泡,可是它們實現的方法不同:
public class SmallBulb { public void electrify() { System.out.println("使用1V電壓給小燈泡通電"); } }
這時候就須要加上一個適配器類了:
/** * 適配器類 */ public class Adapter implements DigitalProducts { private SmallBulb smallBulb = new SmallBulb(); public void charge() { smallBulb.electrify(); } }
這樣在客戶端上就可使用統一的接口了:
package org.zero01.client; public class Client { public static void main(String[] args) { DigitalProducts phone = new Phone(); DigitalProducts ipad = new IPad(); DigitalProducts macBook = new MacBook(); DigitalProducts samllBulb = new Adapter(); phone.charge(); ipad.charge(); macBook.charge(); samllBulb.charge(); } }
運行結果:
手機使用4v電壓充電 平板使用6v電壓充電 筆記本電腦使用14v電壓充電 使用1V電壓給小燈泡通電