設計模式之適配器模式

適配器模式

一:適配器模式概述

​ 適配器其實你們都知道,好比電源適配器,筆記本電壓20多V,而家庭用電220V,因此咱們必須解決讓20v左右的筆記本在220V環境下工做,那麼便須要電源適配器了java

​ 與電源適配器類似,在適配器模式中引入了一個被稱爲適配器(Adapter)的包裝類,而它所包裝的對象稱爲適配者(Adaptee),即被適配的類。適配器的實現就是把客戶類的請求轉化爲對適配者的相應接口的調用。也就是說:當客戶類調用適配器的方法時,在適配器類的內部將調用適配者類的方法,而這個過程對客戶類是透明的,客戶類並不直接訪問適配者類。所以,適配器讓那些因爲接口不兼容而不能交互的類能夠一塊兒工做。app

​ 適配器模式能夠將一個類的接口和另外一個類的接口匹配起來,而無須修改原來的適配者接口和抽象目標類接口。適配器模式定義以下:ide

將一個接口轉換成客戶但願的另外一個接口,使接口不兼容的那些類能夠一塊兒工做,其別名爲包裝器(Wrapper)。適配器模式既能夠做爲類結構型模式,也能夠做爲對象結構型模式。this

​ 在適配器模式中,咱們經過增長一個新的適配器類來解決接口不兼容的問題,使得本來沒有任何關係的類能夠協同工做。根據適配器類與適配者類的關係不一樣,適配器模式可分爲對象適配器類適配器兩種,在對象適配器模式中,適配器與適配者之間是關聯關係;在類適配器模式中,適配器與適配者之間是繼承(或實現)關係。在實際開發中,對象適配器的使用頻率更高。spa


二:對象適配器結構圖

1545722731275

角色說明:code

  • Target(目標抽象類):目標抽象類定義客戶所需接口,能夠是一個抽象類或接口,也能夠是具體類。
  • Adapter(適配器類):適配器能夠調用另外一個接口,做爲一個轉換器,對Adaptee和Target進行適配,適配器類是適配器模式的核心,在對象適配器中,它經過繼承Target並關聯一個Adaptee對象使兩者產生聯繫。
  • Adaptee(適配者類):適配者即被適配的角色,它定義了一個已經存在的接口,這個接口須要適配,適配者類通常是一個具體類,包含了客戶但願使用的業務方法,在某些狀況下可能沒有適配者類的源代碼。

根據對象適配器模式結構圖,在對象適配器中,客戶端須要調用request()方法,而適配者類Adaptee沒有該方法,可是它所提供的specificRequest()方法倒是客戶端所須要的。爲了使客戶端可以使用適配者類,須要提供一個包裝類Adapter,即適配器類。這個包裝類包裝了一個適配者的實例,從而將客戶端與適配者銜接起來,在適配器的request()方法中調用適配者的specificRequest()方法。由於適配器類與適配者類是關聯關係(也可稱之爲委派關係),因此這種適配器模式稱爲對象適配器模式。客戶端只看到目標接口而不是適配器。適配器實現目標接口。適配器將全部請求委託給Adapteecdn

三:案例分析

假設你有一個帶有fly()和makeSound()<發出聲音類>方法的Bird類。還有一個帶有squeak()<吱吱叫類>方法的ToyDuck類。假設鳥是咕咕叫,鴨子是吱吱叫,實現了不一樣的接口,如今我但願鴨子發出鳥叫聲。因此咱們將使用適配器模式。在這裏,咱們的客戶將是ToyDuck,而adaptee將是Bird。對象

1545723558692

如圖:BirdAdapter將實現ToyDuck接口,類中將關聯一個Bird類,接口,當調用Squea()接口時,適配器將調用Bird接口的makeSound方法,從而實現鴨子發出鳥叫聲的功能。blog

角色分析:繼承

Bird:

// 鳥類實現接口容許飛行和發出 聲音
public interface Bird {
    public void fly();
    public void makeSound();
}
複製代碼

Sparrow:

// 麻雀
public class Sparrow implements Bird {
    @Override
    public void fly() {
        System.out.println("正在飛");
    }
    @Override
    public void makeSound() {
        System.out.println("咕咕叫");
    }
}
複製代碼

ToyDuck:

// 玩具鴨要實現的接口,不會飛,只會吱吱叫
public interface ToyDuck {
    // 吱吱吱叫
    public void squeak();
}
複製代碼

PlasticToyDuck:

// 塑料玩具鴨
public class PlasticToyDuck implements ToyDuck{
    @Override
    public void squeak() {
        System.out.println("吱吱叫");
    }
}
複製代碼

BirdAdapter:

public class BirdAdapter implements ToyDuck {
    // 須要實現客戶端但願使用的接口
    Bird bird;
    public BirdAdapter(Bird bird) {
        // 須要引用正在使用的對象
        this.bird = bird;
    }

    @Override
    public void squeak() {
        bird.makeSound();
    }
}
複製代碼

client:

public class Client {
    public static void main(String[] args) {
        // 麻雀(適配者 Adaptee,被適配的類)
        Bird sparrow = new Sparrow();
        // 適配器(adapter)
        ToyDuck birdAdapter = new BirdAdapter(sparrow);

        // 玩具鴨表現的像一隻鳥
        System.out.println("我是鴨子,但我發出鳥叫聲:");
        birdAdapter.squeak();
    }
}
複製代碼

我是鴨子,但我發出鳥叫聲: 咕咕叫

四:類適配器結構圖

1545724369779

這是類適配器結構圖,adapter須要繼承自目標對象並實現接口,而不少語言都不支持多重繼承,因此這種模式不多使用。


五:適配器模式總結

好處:

  • 將目標類和適配者類解耦,經過引入一個適配器類來重用現有的適配者類,無須修改原有結構。。
  • 客戶端類並不複雜,必須使用不一樣的接口,而且可使用多態在不一樣的適配器實現之間進行交換。
  • 增長了類的透明性和複用性,將具體的業務實現過程封裝在適配者類中,對於客戶端類而言是透明的,並且提升了適配者的複用性,同一個適配者類能夠在多個不一樣的系統中複用
  • 靈活性和擴展性都很是好,經過使用配置文件,能夠很方便地更換適配器,也能夠在不修改原有代碼的基礎上增長新的適配器類,徹底符合「開閉原則」。

對象適配器優點:

  • 一個對象適配器能夠把多個不一樣的適配者適配到同一個目標
  • 能夠適配一個適配者的子類,因爲適配器和適配者之間是關聯關係,根據「里氏代換原則」,適配者的子類也可經過該適配器進行適配。

對象適配器的劣勢:

  • 要在適配器中置換適配者類的某些方法比較麻煩。若是必定要置換掉適配者類的一個或多個方法,能夠先作一個適配者類的子類,將適配者類的方法置換掉,而後再把適配者類的子類當作真正的適配者進行適配,實現過程較爲複雜。

缺點:

  • 全部請求都被轉發,所以開銷略有增長。
  • 有時須要在適配器鏈上進行許多調整以達到所需的類型。

使用場景:

  • 系統須要使用一些現有的類,而這些類的接口(如方法名)不符合系統的須要,甚至沒有這些類的源代碼
  • 想建立一個能夠重複使用的類,用於與一些彼此之間沒有太大關聯的一些類,包括一些可能在未來引進的類一塊兒工做。
相關文章
相關標籤/搜索