週末窩在家裏面打王者榮耀,女友在旁邊玩個人電腦,我嫌她播放的綜藝節目聲音比較大,因而建議她戴耳機。設計模式
Adapter Pattern,一般被翻譯成適配器模式,有時候也叫作包裝模式(wrapper pattern),是GOF 23種設計模式之一。主要做用是將一個類的接口轉換成客戶但願的另一個接口。適配器模式使得本來因爲接口不兼容而不能一塊兒工做的那些類能夠一塊兒工做。bash
《Design Patterns: Elements of Reusable Object-Oriented Software》(《設計模式》),由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 合著(Addison-Wesley,1995)。這幾位做者常被稱爲"Gang of Four),簡稱GOF。markdown
GOF中將適配器模式分爲類適配器模式和對象適配器模式。app
對象適配器模式框架
在這種適配器模式中,適配器容納一個它包裹的類的實例。在這種狀況下,適配器調用被包裹對象的物理實體。iphone
類適配器模式ide
這種適配器模式下,適配器繼承自已實現的類(通常多重繼承)。oop
兩者區別僅在於適配器角色對於被適配角色的適配是經過繼承仍是組合來實現的,因爲Java中不支持多繼承,並且類適配器模式有破壞封裝之嫌,並且咱們也提倡多用組合少用繼承。因此本文主要介紹對象適配器。學習
咱們生活中常常須要用到插口轉換器,好比如今不少手機都只有一個插口,這個口能夠直接用來充電和聽音樂。可是前提是咱們使用的充電器和耳機的插口要和這個設備適配的。this
目前市面上不少手機的插口都是type-c或者Lightning型號:
可是,咱們經常使用的耳機型號倒是2.5mm和3.5mm的圓形接口:
一、系統須要使用現有的類,而此類的接口不符合系統的須要。
二、想要創建一個能夠重複使用的類,用於與一些彼此之間沒有太大關聯的一些類,包括一些可能在未來引進的類一塊兒工做,這些源類不必定有一致的接口。
三、經過接口轉換,將一個類插入另外一個類系中。(好比老虎和飛禽,如今多了一個飛虎,在不增長實體的需求下,增長一個適配器,在裏面包容一個虎對象,實現飛的接口。)
適配器模式,就能夠解決以上的問題。
下面咱們就使用適配器模式,模擬一種場景:使用一個安卓的type-c充電器給只支持 Lightning接口的蘋果手機充電(假設能夠完美支持)。
已知,咱們有一個type-c充電器、一個Lightning插口的蘋果手機。不管是type-c仍是Lightning,都是一種標準,在代碼中,標準即接口。因此咱們先定義兩個接口:
/**
* Lightning充電接口
*/
public interface LightningInterface {
public void chargeWithLightning();
}
/**
* TypeC充電接口
*/
public interface TypeCInterface {
public void chargeWithTypeC();
}複製代碼
接下來定義咱們的蘋果手機,他只支持使用 Lightning插口充電:
public class IphoneX { private LightningInterface lightningInterface; public IphoneX() { } public IphoneX(LightningInterface lightningInterface) { this.lightningInterface = lightningInterface; } public void charge() { System.out.println("開始給個人IphoneX手機充電..."); lightningInterface.chargeWithLightning(); System.out.println("結束給個人IphoneX手機充電..."); } //setter/getter }複製代碼
而後再來看看咱們的安卓充電器應該如何定義:
/** * 安卓設備的充電器 */ public class AndroidCharger implements TypeCInterface { @Override public void chargeWithTypeC() { System.out.println("使用Type-C型號的充電器充電..."); } }複製代碼
有了安卓充電器和蘋果手機。接下來,咱們就要定義一個適配器了,但願經過這個適配器,咱們能夠實現使用安卓設備的充電器給蘋果手機充電:
public class Adapter implements LightningInterface { private TypeCInterface typeCInterface; public Adapter() { } public Adapter(TypeCInterface typeCInterface) { typeCInterface = typeCInterface; } @Override public void chargeWithLightning() { typeCInterface.chargeWithTypeC(); } //setter/getter }複製代碼
這個適配器實現了LightningInterface,並組合了TypeCInterface,當外部調用chargeWithLightning方法的時候,實際上調用的是typeCInterface.chargeWithTypeC方法。
就像電源適配器,他實現的是一個Lightning的規範,自身是一個Lightning的插頭,但實際充電的時候,他是經過typc-c的電源進行的,他起到的是一箇中間轉換的做用。
接着咱們定義客戶端,實現咱們想要的充電功能:
public class Main {
public static void main(String[] args) {
Adapter adapter = new Adapter(new AndroidCharger());
IphoneX iphoneX = new IphoneX();
iphoneX.setLightningInterface(adapter);
iphoneX.charge();
}
}複製代碼
輸出結果以下:
開始給個人IphoneX手機充電...
使用Type-C型號的充電器充電...
結束給個人IphoneX手機充電...複製代碼
上面的例子經過適配器,咱們使用一個安卓的type-c充電器給一個只支持Lightning接口的蘋果手機充電。
上面的代碼,就是一個適配器模式的例子,這個例子中,共出現了四種角色:
優勢
適配器模式(對象適配器模式),是一種組合優於集成的思想的實現。經過使用適配器模式,咱們能夠最大程度的複用已有的了類和代碼。他主要有如下有點:
將目標類和適配者類解耦,經過引入一個適配器類來重用現有的適配者類,而無須修改原有代碼。
增長了類的透明性和複用性,將具體的實現封裝在適配者類中,對於客戶端類來講是透明的,並且提升了適配者的複用性。
靈活性和擴展性都很是好,經過使用配置文件,能夠很方便地更換適配器,也能夠在不修改原有代碼的基礎上增長新的適配器類,徹底符合「開閉原則」。
缺點
固然,適配器模式並非完美的,過分使用仍是會帶來一些問題的。缺點以下:
過多地使用適配器,會讓系統很是零亂,不易總體進行把握。好比,明明看到調用的是 A 接口,其實內部被適配成了 B 接口的實現,一個系統若是太多出現這種狀況,無異於一場災難。所以若是不是頗有必要,能夠不使用適配器,而是直接對系統進行重構。
關於適配器模式的使用場景,通常主要是當咱們須要修改一些正在運行着的代碼,而且但願能夠複用原有代碼實現新的功能的時候,就要考慮適配器模式。
在Spring框架中,就大量的使用了適配器模式,讀者能夠打開本身的IDE,嘗試着以關鍵字"Adapter"全局搜索下,必定會有不少的實際應用。
當你遇到的問題,和你想用安卓充電器給蘋果手機充電相似的時候,就必定要想到適配器模式哦!
這是關於設計模式的第三篇,前兩篇分別是:《漫話:如何給女友解釋什麼是策略模式?》《漫話:如何給女友解釋什麼是單例模式?》還想學習哪一種設計模式,歡迎留言哦。