適配器模式:我真的不難

前面三篇文章分別學習了單例模式、三種工廠模式和建造者模式,它們都是比較經常使用的建立型模式,顧名思義就是建立對象的。從這篇文章開始來學習結構型設計模式,今天是第一篇——適配器模式。java

適配器模式

首先拿我使用的小米手機爲例,它撤銷了原來的 Audio 接口,要使用耳機聽歌呢,就必須使用 Type-C to Audio 轉接線(以下圖),一頭接上手機,一頭接上耳機線。(ps:話說,每次聽歌和充電都要換來換去的,好麻煩)設計模式

其實,這就是一個實際的適配器,和設計模式中的適配器扮演着一樣的角色,將一個接口轉換爲另外一個接口,以符合用戶的指望。ide

改進前

下面咱們就將這個例子轉換爲代碼,看它是如何實現的。之前的手機呢,有兩個接口,使用 TypeC 接口充電:post

public interface TypeCInterface {
    // 充電
    void chargeWithTypeC();
}

public class TypeCInterfaceImpl implements TypeCInterface {

    @Override
    public void chargeWithTypeC() {
        System.out.println("使用 Type-C 接口充電");
    }
}
複製代碼

使用 Audio 接口聽歌:學習

public interface AudioInterface {
    // 聽歌
    void listenWithAudio();
}

public class AudioInterfaceImpl implements AudioInterface {

    @Override
    public void listenWithAudio() {
        System.out.println("使用 Audio 接口聽歌");
    }
}
複製代碼

而咱們的手機,同時有這兩個接口,用來充電和聽歌:this

public class XiaomiPhone {

    private AudioInterface audioInterface;
    private TypeCInterface typeCInterface;
    
    public XiaomiPhone(AudioInterface audioInterface, TypeCInterface typeCInterface) {
        this.audioInterface = audioInterface;
        this.typeCInterface = typeCInterface;
    }
    
    public void charge() {
        typeCInterface.chargeWithTypeC();
    }
    
    public void listen() {
        audioInterface.listenWithAudio();
    }
}
複製代碼

而咱們就能夠用手機來邊充電,邊聽歌了:spa

public class Client {

    public static void main(String[] args) {
        AudioInterface audioInterface = new AudioInterfaceImpl();
        TypeCInterface typeCInterface = new TypeCInterfaceImpl();
        
        XiaomiPhone xiaomiPhone = new XiaomiPhone(audioInterface, typeCInterface);
        xiaomiPhone.charge();
        xiaomiPhone.listen();
    }
}
複製代碼

改進了

原本這一切都好好的,但是小米手機把 Audio 接口取消了,咱們無法直接使用來聽歌了。因而,咱們只好使用轉接線,將 Type-C 接口轉爲 Audio 接口:設計

// 需將其轉換爲 Audio 接口,因此實現了 AudioInterface
public class TypeCToAudioTieline implements AudioInterface {

    private TypeCInterface typeCInterface;

    // 另外一頭是 TypeC,因此傳入 TypeCInterface
    public TypeCToAudioTieline(TypeCInterface typeCInterface) {
        this.typeCInterface = typeCInterface;
    }

    @Override
    public void listenWithAudio() {
        // ···
        typeCInterface.chargeWithTypeC();
    }
}
複製代碼

而後呢,把轉接線插入到手機上(把手機和轉接線看做一個總體,它只有 Audio 接口了):code

public class XiaomiPhone {

    private AudioInterface audioInterface;

    public XiaomiPhone(AudioInterface audioInterface) {
        this.audioInterface = audioInterface;
    }

    public void listenWithAudio() {
        audioInterface.listenWithAudio();
    }
}
複製代碼

因而,如今咱們就經過轉接線,將 Type-C 接口轉換成了 Audio 接口。而後將耳機插在轉接線上,就能夠聽歌了:cdn

public class Client {

    public static void main(String[] args) {
        TypeCInterface typeCInterface = new TypeCInterfaceImpl();
        TypeCToAudioTieline tieline = new TypeCToAudioTieline(typeCInterface);

        XiaomiPhone xiaomiPhone = new XiaomiPhone(tieline);
        xiaomiPhone.listenWithAudio();
    }
}
複製代碼

上述模式就是適配器模式,它將一個類的接口轉換成用戶所須要的另外一個接口,使得本來接口不兼容的類能夠一塊兒工做。

它的 UML 圖以下:

下面咱們來總結適配器模式的優勢:

  • 它能夠經過適配器進行接口的轉換,讓本來不兼容的類協同工做;
  • 這可使客戶從實現的接口解耦,若是被適配者改變了接口,適配器能夠將其封裝起來,客戶沒必要跟隨其修改;

缺點:

  • 增長一個適配器,可能會增長系統的複雜度。

適配器模式的具體實踐

JDK#InputStreamReader

經過 InputStreamReader,能夠將 InputStream 字節流轉換爲字符流進行處理。

public class InputStreamReader extends Reader {

    private final StreamDecoder sd;
    
    // 將 inputStream 轉換爲 InputStreamReader
    public InputStreamReader(InputStream in) {
        super(in);
        try {
            sd = StreamDecoder.forInputStreamReader(in, this, (String)null); // ## check lock object
        } catch (UnsupportedEncodingException e) {
            throw new Error(e);
        }
    }
    
    public int read() throws IOException {
        return sd.read();
    }
}
複製代碼

Spring#AOP/MVC

另外,好比在 Spring AOP 中,將 Advice 封裝成對應的攔截器類型。或是在 Spring MVC 中,經過適配器模式,用於執行目標 Controller 中的請求處理方法。

因爲對其源碼不太熟悉,這裏也就不詳細說了。感興趣的小夥伴能夠看看這篇文章。

相關文章
相關標籤/搜索