設(shè)計模式詳解——適配器模式

前言
今天我們來看另一個和包裝有關(guān)的設(shè)計模式——適配器模式,和裝飾者模式比起來,它更像是一位無名耕耘者,隱身于溝渠之中,干著臟活累活——轉(zhuǎn)換接口。用時下比較火的一個詞來比喻這種設(shè)計模式的話,那就是女裝大佬,這真的是適配器模式最佳類比了,我相信你看完今天的所有內(nèi)容,一定會明白的
適配器模式
適配器模式將一個類的接口,轉(zhuǎn)換成客戶期望的另一個接口,適配器讓原本不兼容的接口可以合作無間。
適配器模式采用的設(shè)計原則是使用對象組件,以修改的接口包裝被適配者,這樣的好處是,被適配者的任何子類,都可以搭配適配器使用。

采用適配器模式之后:

要點(diǎn)
適配器模式主要是為了在不改變原有接口的基礎(chǔ)上,適配客戶新的接口 當(dāng)需要使用一個現(xiàn)有的類而其接口并不符合你的需要時,就使用適配器模式 適配器有兩種形式:對象適配器和類適配器。類適配器需要用到多重繼承 適配器將一個對象包裝起來以改變其接口;裝飾者將一個對象包裝起來以增加新的行為和屬性;而外觀模式將一群對象“包裝”起來以簡化其接口
示例代碼
從網(wǎng)上搜了一些適配器的示例,但是最后發(fā)現(xiàn)還是沒有《Head First設(shè)計模式》中的簡單,所以最后我還是用了書上的示例。
示例的場景是這樣的:假設(shè)客戶需要一只鴨子,但是我們手里只有火雞,這時候?yàn)榱藵M足客戶的需求,我們必須通過適配器將火雞轉(zhuǎn)換成鴨子。
下面就是整個實(shí)現(xiàn)過程:
原始系統(tǒng)接口
首選我們拿到鴨子的接口,其中有兩個方法,一個是鳴叫,一個是飛
public?interface?Duck?{
????void?quack();
????void?fly();
}
接口實(shí)現(xiàn)類
這個是鴨子的實(shí)現(xiàn),這是僅僅是為了后期測試。因?yàn)槲覀儸F(xiàn)在沒有這個實(shí)現(xiàn),所以后面要適配這樣一個對象。
public?class?MallardDuck?implements?Duck?{
????@Override
????public?void?quack()?{
????????System.out.println("quack");
????}
????@Override
????public?void?fly()?{
????????System.out.println("I'm?flying");
????}
}
被適配對象接口
這個是我們火雞的原始接口,也就是我們要適配成鴨子的火雞的基類,也有兩個方法,一個是鳴叫,一個是飛。
public?interface?Turkey?{
????void?gobble();
????void?fly();
}
火雞的實(shí)現(xiàn)類:
public?class?WildTurkey?implements?Turkey?{
????@Override
????public?void?gobble()?{
????????System.out.println("gobble?gobble");
????}
????@Override
????public?void?fly()?{
????????System.out.println("I'm?flying?a?short?distance");
????}
}
適配器實(shí)現(xiàn)
這里就是火雞適配鴨子的適配器,首先它要實(shí)現(xiàn)鴨子的接口,然后我們定義一個火雞屬性,用于接收我們的火雞實(shí)例,再然后我們將火雞的鳴叫和飛的方法分別封裝到鴨子的對應(yīng)方法,因?yàn)橐且恢憋w,火雞是普魯普魯飛,所以要多次飛。至此 ,火雞適配鴨子的適配操作就完成了,下面我們測試下。
public?class?TurkeyAdapter?implements?Duck?{
????Turkey?turkey;
????public?TurkeyAdapter(Turkey?turkey)?{
????????this.turkey?=?turkey;
????}
????@Override
????public?void?quack()?{
????????turkey.gobble();
????}
????@Override
????public?void?fly()?{
????????for?(int?i?=?0;?i?5;?i++)?{
????????????turkey.fly();
????????}
????}
}
測試代碼
這里我們分別創(chuàng)建了鴨子、火雞和適配了鴨子的火雞的示例,演示他們的執(zhí)行過程:
?@Test
????public?void?testDuck()?{
????????MallardDuck?duck?=?new?MallardDuck();
????????WildTurkey?turkey?=?new?WildTurkey();
????????TurkeyAdapter?turkeyAdapter?=?new?TurkeyAdapter(turkey);
????????System.out.println("火雞:");
????????turkey.gobble();
????????turkey.fly();
????????System.out.println("=============\n綠頭鴨:");
????????duck.quack();
????????duck.fly();
????????System.out.println("=============\n火雞適配的鴨子:");
????????turkeyAdapter.quack();
????????turkeyAdapter.fly();
????}
從代碼中我們可以看到,這里適配了鴨子的火雞像鴨子一樣執(zhí)行了quack和fly操作
運(yùn)行結(jié)果:

總結(jié)
從上面的示例中,我們可以很清楚的看到,適配器模式本質(zhì)上就是類型的轉(zhuǎn)換,除了我們這里的例子,日常生活中還有很多類似的例子,比如電腦顯示器VGA轉(zhuǎn)HDMI、用電設(shè)備插頭轉(zhuǎn)換等:


雖然都是類型的包裝和轉(zhuǎn)換,但是適配器模式和裝飾者模式是有本質(zhì)區(qū)別的,裝飾者模式始終是同同一種類型的包裝和轉(zhuǎn)換,也就是說所有的包裝類與被包裝類,本質(zhì)上都是同一種類型,但是在適配器中,轉(zhuǎn)換和包裝的一定是不同的類型,比如火雞到鴨子。
最后引用一段話來結(jié)束今天的內(nèi)容:
- END -如果它走起來像只鴨子,叫起來像只鴨子,那么它必定可能是一只鴨子包裝了鴨子適配器的火雞……
