學(xué)好設(shè)計(jì)模式防被祭天:適配器模式

適配器模式

為了防止被“殺”了祭天,學(xué)點(diǎn)設(shè)計(jì)模式,并總結(jié)下還是有必要的。

一:理解

  1. 適配器模式讓一個(gè)類的接口,轉(zhuǎn)換成客戶期望的另一個(gè)接口。適配器讓原本接口不兼容的類可以合作無間?!禜ead First設(shè)計(jì)模式》
  2. 適配器模式在生活中也經(jīng)常用到,如不同標(biāo)準(zhǔn)的插座適配器。


二:例子

你是個(gè)富二代。

在全新MacBook上市之后,你準(zhǔn)備給你司兩萬多名員工換上最新的Mac。

但你發(fā)現(xiàn),新的MacBook只有TypeC接口,之前那些使用HDMI接口連接的顯示屏都不能用,氣得你都想打人。

只有TypeC接口

你希望Mac可以適配以下這些接口。

希望適配的接口

于是,你找到了程序員小菜幫忙解決這個(gè)接口適配問題。

小菜表示,新款Mac只提供TypeC接口,怪我咯。

怪我咯

不過,由于你是富二代,小菜也只能乖乖地敲起了代碼。

他首先抽象了TypeC接口,和一個(gè)TypeC類:

public interface TypeCInterface {
    void connectTypeC(String device, String port);
}

public class TypeC implements TypeCInterface {
    @Override
    public void connectTypeC(String device, String port) {
        if (StringUtils.equals(port, "typeC")) {
            System.out.println("使用TypeC接口連接" + device);
        } else {
            throw new UnsupportedOperationException("Not supported");
        }
    }
}

TypeCInterface接口中申明了connectTypeC方法,兩個(gè)參數(shù)device和port,表示待連接設(shè)備的名稱和接口。例如使用HDMI連接的顯示屏,使用USB接口連接的U盤等。

TypeC類實(shí)現(xiàn)TypeCInterface接口,并實(shí)現(xiàn)connectTypeC方法,該方法需要檢查待連接的設(shè)備是否使用typeC接口,符合要求才進(jìn)行連接,否則拋出不支持操作異常。

小菜接著抽象了MacBook類:

@Data
public class MacBook {
    private TypeCInterface typeC;

    public void connect(String device, String port) {
        typeC.connectTypeC(device, port);
    }
}

MacBook包含一個(gè)typeC接口,和一個(gè)連接方法,連接時(shí)只能通過TypeC接口連接,即調(diào)用typeC屬性的connectTypeC方法。

小菜寫了一段測試代碼,分別嘗試在MacBook上連接typeC接口的顯示屏和hdmi接口的顯示屏。

public class Client {
    public static void main(String[] args) {
        TypeCInterface macTypeC = new TypeC();
        MacBook macBook = new MacBook();
        macBook.setTypeC(macTypeC);
        macBook.connect("Display", "typeC");
        macBook.connect("Display", "hdmi");
    }
}

輸入/輸出:

使用TypeC接口連接Display
Exception in thread "main" java.lang.UnsupportedOperationException: Not supported

結(jié)果很明顯,新款MacBook不支持HDMI接口的顯示屏。

為了能連接HDMI接口的顯示屏,他又抽象了HDMI接口,和一個(gè)HDMI類:

public interface HDMIInterface {
    void connectHDMI(String device, String equipment);
}

public class HDMI implements HDMIInterface {
    @Override
    public void connectHDMI(String device, String port) {
        if (StringUtils.equals(port, "hdmi")) {
            System.out.println("使用HDMI接口連接" + device);
        } else {
            throw new UnsupportedOperationException("Not supported");
        }
    }
}

HDMI接口和類的定義和TypeC接口類似。

然而MacBook是無法拆的,不能在Mac上增加一個(gè)HDMI接口。

于是小菜想到可以在某寶上買個(gè)適配器來解決這個(gè)問題。

TypeC HDMI適配器

很顯然的,這個(gè)接口需要符合以下兩點(diǎn)要求:

  1. 實(shí)現(xiàn)TypeC接口,用于連接MacBook,即將該接口的對(duì)象set進(jìn)MacBook的typeC屬性中。
  2. 支持連接實(shí)現(xiàn)HDMI接口的設(shè)備。

小菜很開心,立馬寫了一個(gè)HDMITypeCAdapter類:

@Data
public class HDMITypeCAdapter implements TypeCInterface {
    HDMIInterface hdmi;

    @Override
    public void connectTypeC(String device, String port) {
        System.out.println("裝上HDMITypeC適配器");
        if (StringUtils.equals(port, "hdmi")) {
            hdmi.connectHDMI(device, port);
        } else {
            throw new UnsupportedOperationException("Not supported");
        }
    }
}

該類實(shí)現(xiàn)了TypeC接口(TypeCInterface),并包含一個(gè)hdmi屬性,表示支持連接實(shí)現(xiàn)了HDMI接口的設(shè)備。

在connectTypeC方法中,首先輸出裝了適配器,然后再調(diào)用hdmi對(duì)象的connectHDMI方法。

連上適配器之后,小菜寫了測試代碼:

public class Client {
    public static void main(String[] args) {
        TypeCInterface macTypeC = new TypeC();
        MacBook macBook = new MacBook();
        macBook.setTypeC(macTypeC);
        macBook.connect("Display", "typeC");

        HDMITypeCAdapter hdmiTypeCAdapter = new HDMITypeCAdapter();
        HDMIInterface macHDMI = new HDMI();
        hdmiTypeCAdapter.setHdmi(macHDMI);
        macBook.setTypeC(hdmiTypeCAdapter);
        macBook.connect("Display", "hdmi");
}

輸入/輸出:

使用TypeC接口連接Display
裝上HDMITypeC適配器
使用HDMI接口連接Display

這就是適配器模式,用上適配器之后,可以讓調(diào)用方MacBook在不改變?cè)写a的情況下,調(diào)用不適配的HDMI接口。

小菜又想到,如果你哪天想要在MacBook上連接其他設(shè)備了怎么辦,只能再買一個(gè)新的適配器,如TypeC轉(zhuǎn)USB適配器。

如果要符合你之前提出的適配多借口的需求,那就需要買多個(gè)適配器。這樣會(huì)變得很麻煩。

于是小菜搜了一下某寶,發(fā)現(xiàn)了一枚神器,多功能適配器。

多功能適配器

小菜抽象了一個(gè)多功能適配器類:

public class MultifunctionTypeCAdapter implements TypeCInterface {
    private static Map<String, Object> portMap = Maps.newHashMap();

    static {
        portMap.put("typeC", new TypeC());
        portMap.put("hdmi", new HDMI());
        portMap.put("usb", new USB());
    }

    @Override
    public void connectTypeC(String device, String port) {
        if (!portMap.containsKey(port)) {
            throw new UnsupportedOperationException("Not supported");
        }
        System.out.println("裝上多功能適配器");
        if (StringUtils.equals(port, "typeC")) {
            ((TypeC) portMap.get("typeC")).connectTypeC(device, port);
        } else if (StringUtils.equals(port, "hdmi")) {
            ((HDMI) portMap.get("hdmi")).connectHDMI(device, port);
        } else if (StringUtils.equals(port, "usb")) {
            ((USB) portMap.get("usb")).connectUSB(device, port);
        }
    }
}

可以看到,多功能TypeC適配器仍舊實(shí)現(xiàn)了TypeC接口,并用一個(gè)Map來保存所有支持的接口,該多功能適配器支持轉(zhuǎn)接TypeC,HDMI和USB。

在connectTypeC方法中,首先判斷portMap中是否包含輸入中指定的接口port,確定之后再進(jìn)行連接。

其中的USB類如下:

public class USB {
    public void connectUSB(String device, String port) {
        if (StringUtils.equals(port, "usb")) {
            System.out.println("使用USB接口連接" + device);
        } else {
            throw new UnsupportedOperationException("Not supported");
        }
    }
}

小菜把多功能TypeC適配器拿給你看,你覺得非常nice,并表示“我覺得OK”。

我覺得OK

于是你興高采烈地去采購了一批多功能適配器。

小菜以為你會(huì)慷慨地獎(jiǎng)勵(lì)他一臺(tái)新的MacBook,開心得像個(gè)兩百斤的孩子。

然而,作為富二代的你,覺得適配器比Mac有意思多了,就決定賞賜小菜幾個(gè)適配器。

適配適配……適配適配器

于是,小菜只能默默地玩起了適配器適配適配器的游戲,并且深藏功與名。


三:再理解

  1. 調(diào)用者持有原有接口屬性,調(diào)用原有接口的方法,并且不能修改。
  2. 調(diào)用者需要調(diào)用新的接口,由于新舊接口不兼容,不能把新接口的對(duì)象直接set進(jìn)調(diào)用者的屬性。
  3. 只能新建一個(gè)實(shí)現(xiàn)老接口的適配器類,持有新接口對(duì)象,在適配器類的方法體內(nèi)調(diào)用新接口的方法。
  4. 當(dāng)需要再次調(diào)用別的新接口時(shí),只需要增加新的適配器類。符合對(duì)增加開放,對(duì)修改關(guān)閉的原則。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容