漫畫:如何給女朋友解釋什麼是適配器模式?
本文經授權轉載自漫話編程(ID:mhcoding)
責編 | 伍杏玲
周末窩在家裡面打王者榮耀,女朋友在旁邊玩我的電腦,我嫌她播放的綜藝節目聲音比較大,於是建議她戴耳機。
適配器模式
Adapter Pattern,通常被翻譯成適配器模式,有時候也叫做包裝模式(Wrapper Pattern),是GOF 23種設計模式之一。主要作用是將一個類的介面轉換成客戶希望的另外一個介面。適配器模式使得原本由於介面不兼容而不能一起工作的那些類可以一起工作。
《Design Patterns: Elements of Reusable Object-Oriented Software》(《設計模式》),由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 合著(Addison-Wesley,1995)。這幾位作者常被稱為"Gang of Four),簡稱GOF。
GOF中將適配器模式分為類適配器模式和對象適配器模式。
對象適配器模式
在這種適配器模式中,適配器容納一個它包裹的類的實例。在這種情況下,適配器調用被包裹對象的物理實體。
類適配器模式
這種適配器模式下,適配器繼承自已實現的類(一般多重繼承)。
二者區別僅在於適配器角色對於被適配角色的適配是通過繼承還是組合來實現的,由於Java中不支持多繼承,而且類適配器模式有破壞封裝之嫌,而且我們也提倡多用組合少用繼承。所以本文主要介紹對象適配器。
適配器模式用途
我們生活中經常需要用到插口轉換器,比如現在很多手機都只有一個插口,這個口可以直接用來充電和聽音樂。但是前提是我們使用的充電器和耳機的插口要和這個設備適配的。
目前市面上很多手機的插口都是Type-C或者Lightning型號:但是,我們常用的耳機型號卻是2.5mm和3.5mm的圓形介面。
所以,當我們想要把自己的3.5mm圓形介面的耳機插入Lightning或者Type-C介面的時候,就需要一個轉換器。
同理,在軟體系統中,常常要將一些"現存的對象"放到新的環境中,而新環境要求的介面是現對象不能滿足。如以下類似的場景:
1、系統需要使用現有的類,而此類的介面不符合系統的需要。
2、想要建立一個可以重複使用的類,用於與一些彼此之間沒有太大關聯的一些類,包括一些可能在將來引進的類一起工作,這些源類不一定有一致的介面。
3、通過介面轉換,將一個類插入另一個類系中。(比如老虎和飛禽,現在多了一個飛虎,在不增加實體的需求下,增加一個適配器,在裡面包容一個虎對象,實現飛的介面。)
適配器模式,就可以解決以上的問題。
適配器模式實現方式
下面我們就使用適配器模式,模擬一種場景:使用一個安卓的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的插頭,但實際充電的時候,他是通過Type-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介面的蘋果手機充電。
上面的代碼,就是一個適配器模式的例子,這個例子中,共出現了四種角色:
以上四個角色中,目標抽象類(Lightning介面)、適配者類(安卓充電器)、客戶端(蘋果手機)都是原來代碼中就有的,我們完全不需要對他們進行修改。只需要引入一個適配器(介面轉換器)即可。
優缺點
優點
適配器模式(對象適配器模式),是一種組合優於集成的思想的實現。通過使用適配器模式,我們可以最大程度的復用已有的了類和代碼。他主要有以下有點:
將目標類和適配者類解耦,通過引入一個適配器類來重用現有的適配者類,而無須修改原有代碼。
增加了類的透明性和復用性,將具體的實現封裝在適配者類中,對於客戶端類來說是透明的,而且提高了適配者的復用性。
靈活性和擴展性都非常好,通過使用配置文件,可以很方便地更換適配器,也可以在不修改原有代碼的基礎上增加新的適配器類,完全符合「開閉原則」。
缺點
當然,適配器模式並不是完美的,過度使用還是會帶來一些問題的。缺點如下:
過多地使用適配器,會讓系統非常零亂,不易整體進行把握。比如,明明看到調用的是 A 介面,其實內部被適配成了 B 介面的實現,一個系統如果太多出現這種情況,無異於一場災難。因此如果不是很有必要,可以不使用適配器,而是直接對系統進行重構。
使用場景
關於適配器模式的使用場景,一般主要是當我們需要修改一些正在運行著的代碼,並且希望可以復用原有代碼實現新的功能的時候,就要考慮適配器模式。
在Spring框架中,就大量的使用了適配器模式,讀者可以打開自己的IDE,嘗試著以關鍵字"Adapter"全局搜索下,一定會有很多的實際應用。
當你遇到的問題,和你想用安卓充電器給蘋果手機充電類似的時候,就一定要想到適配器模式哦!
【End】
※想要推翻 5 毛特效,國產影視動畫究竟該如何製作?
※不寫一行代碼就能玩轉 Kaggle 競賽?
TAG:CSDN |