漫话:如何给女朋友解释什么是适配器模式?
本文經授權轉載自微信公眾號:漫話編程
周末窩在家里面打王者榮耀,女朋友在旁邊玩我的電腦,我嫌她播放的綜藝節目聲音比較大,于是建議她戴耳機。
適配器模式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();}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}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?AndroidCharger?implements?TypeCInterface?{
????
????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}class?Adapter?implements?LightningInterface?{????private?TypeCInterface?typeCInterface;
????public?Adapter()?{
????}
????public?Adapter(TypeCInterface?typeCInterface)?{
????????typeCInterface?=?typeCInterface;
????}
????
????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();????????}}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型號的充電器充電...
結束給我的IphoneX手機充電...
上面的例子通過適配器,我們使用一個安卓的type-c充電器給一個只支持Lightning接口的蘋果手機充電。
上面的代碼,就是一個適配器模式的例子,這個例子中,共出現了四種角色:
以上四個角色中,目標抽象類(Lightning接口)、適配者類(安卓充電器)、客戶端(蘋果手機)都是原來代碼中就有的,我們完全不需要對他們進行修改。只需要引入一個適配器(接口轉換器)即可。優缺點優點
適配器模式(對象適配器模式),是一種組合優于集成的思想的實現。通過使用適配器模式,我們可以最大程度的復用已有的了類和代碼。他主要有以下有點:
將目標類和適配者類解耦,通過引入一個適配器類來重用現有的適配者類,而無須修改原有代碼。
增加了類的透明性和復用性,將具體的實現封裝在適配者類中,對于客戶端類來說是透明的,而且提高了適配者的復用性。
靈活性和擴展性都非常好,通過使用配置文件,可以很方便地更換適配器,也可以在不修改原有代碼的基礎上增加新的適配器類,完全符合“開閉原則”。
缺點
當然,適配器模式并不是完美的,過度使用還是會帶來一些問題的。缺點如下:
過多地使用適配器,會讓系統非常零亂,不易整體進行把握。比如,明明看到調用的是 A 接口,其實內部被適配成了 B 接口的實現,一個系統如果太多出現這種情況,無異于一場災難。因此如果不是很有必要,可以不使用適配器,而是直接對系統進行重構。
使用場景
關于適配器模式的使用場景,一般主要是當我們需要修改一些正在運行著的代碼,并且希望可以復用原有代碼實現新的功能的時候,就要考慮適配器模式。
在Spring框架中,就大量的使用了適配器模式,讀者可以打開自己的IDE,嘗試著以關鍵字"Adapter"全局搜索下,一定會有很多的實際應用。
當你遇到的問題,和你想用安卓充電器給蘋果手機充電類似的時候,就一定要想到適配器模式哦!
這是關于設計模式的第三篇,前兩篇分別是:《漫話:如何給女朋友解釋什么是策略模式?》《漫話:如何給女朋友解釋什么是單例模式?》還想學習哪種設計模式,歡迎留言哦。
總結
以上是生活随笔為你收集整理的漫话:如何给女朋友解释什么是适配器模式?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: UVA 10142 Australian
- 下一篇: 2019年容器突然火了,到底什么是容器?