1 初步認識
介面卡模式的定義
將一個類的介面轉成客戶期望的另外一個介面。介面卡模式使得原本由於介面不匹配而不能一起工作的那些類可以一起工作。
大白話
介面卡模式就像旅行插座轉換器(圖1)、Type-c轉VGA轉介面(圖4)一樣。
圖1. 圖片來源網路
圖2. 圖片來源網路
去過香港杜拜等的同學都知道,那邊用的插座跟我們不一樣,他們的插座需要如圖2第1面所示的插頭,而我們常用的插座類似第2面。因此我們的膝上型電腦,手機在當地不能直接充電。所以就需要一個插座轉換器,轉換器第1面插入當地的插座,第2面供我們充電,這樣使得我們的插頭在當地能使用。Type-c轉VGA轉介面也是一樣的道理。
2 介面卡模式結構圖
圖3. 適配模式結構圖 來源網路
如圖所示,Client不能直接訪問Adaptee。Adapter是介面卡,它將Adaptee轉換成Client能訪問的介面。所以通過介面卡Adapter,使用者端就可以訪問Adaptee。
3 使用場景例子
手機想要投影到投影儀上,由於手機是Type-c介面,投影儀是VGA介面。不能直接投影,需要一個介面卡,將視訊訊號從Type-c口轉到VGA口,最後才能輸出到大螢幕上。
4 介面卡模式在使用場景的具體實現
圖4. typec轉vga/hdm轉換器
如圖所示,這有一個介面卡,一號口是typec口,二號口是vga口,只有將視訊訊號從typec口輸入,轉換輸出到vga口,才能和投影儀對接,實現手機螢幕投影到投影儀上的任務。涉及的物品有:手機、介面卡、投影儀。
4.1 定義一個手機,它有個typec口,這是視訊源。
package com.jstao.adapter; /** * @author jstao * 定義一個手機Phone,它有一個Typec介面。 * */ public class Phone { public void typecPhone() { System.out.println("資訊從Typec口的手機輸出。"); } }
4.2 定義一個vga介面
package com.jstao.adapter; /** * @author jstao * 定義一個VGA介面。 * */ public interface Vga { void vgaInterface(); }
4.3 實現一個介面卡,介面卡實現方式分三類:類的介面卡模式、物件的介面卡模式、介面的介面卡模式。
4.3.1 類的介面卡模式
原理:通過繼承特性來實現介面卡功能。
package com.jstao.adapter; /** * * 實現一個Type-c轉VGA介面卡, * 介面卡實現方式有三種,這是第一種實現方式。 * @author jstao * */ public class Typec2Vga1 extends Phone implements Vga{ @Override public void vgaInterface() { // TODO Auto-generated method stub typecPhone(); System.out.println("接收到Type-c口資訊,資訊轉換成VGA介面中..."); System.out.println("資訊已轉換成VGA介面,螢幕可以對接。"); } }
4.3.2 物件的介面卡模式
原理:通過組合方式來實現介面卡功能。
package com.jstao.adapter; /** * * 實現一個Type-c轉VGA介面卡, * 介面卡實現方式有三種,這是第二種實現方式。 * @author jstao * */ public class Typec2Vga2 implements Vga{ private Phone phone; public Typec2Vga2(Phone phone) { // TODO Auto-generated constructor stub this.phone = phone; } @Override public void vgaInterface() { // TODO Auto-generated method stub if(phone != null) { phone.typecPhone(); System.out.println("接收到Type-c口資訊,資訊轉換成VGA介面中..."); System.out.println("資訊已轉換成VGA介面,螢幕可以對接。"); } } }
4.3.3 介面的介面卡模式
原理:藉助抽象類來實現介面卡功能。
定義三個介面
package com.jstao.adapter; /** * 定義介面 * @author jstao * */ public interface Target { void typec(); void typec2vga(); void typec2hdmi(); }
定義一個抽象類
package com.jstao.adapter; /** * 定義一個抽象類 * @author jstao * */ public abstract class Adapter implements Target{ public void typec() { } public void typec2vga() { } public void typec2hdmi() { } }
實現一個VGA介面卡
package com.jstao.adapter; /** * * 實現一個VGA介面卡,同理還可以實現一個HDMI介面卡 * 介面卡實現方式有三種,這是第三種實現方式。 * @author jstao * */ public class VgaAdapter extends Adapter{ public void typec() { System.out.println("資訊從Typec口的手機輸出。"); } public void typec2vga() { System.out.println("接收到Type-c口資訊,資訊轉換成VGA介面中..."); System.out.println("資訊已轉換成VGA介面,螢幕可以對接。"); } }
4.4 定義一個螢幕,用來測試上面實現的三個介面卡
package com.jstao.adapter; /** * 定義一個螢幕 * 與介面卡對接 * @author jstao * */ public class Screen { public static void main(String[] args) { //第一種介面卡用法 System.out.println("-------------第一種介面卡------------"); Vga vga = new Typec2Vga1(); vga.vgaInterface();//介面卡將typec轉換成vga System.out.println("螢幕對接介面卡,手機成功投影到螢幕!"); //第二種介面卡用法 System.out.println("-------------第二種介面卡------------"); Typec2Vga2 typec2Vga1 = new Typec2Vga2(new Phone()); typec2Vga1.vgaInterface();//介面卡將typec轉換成vga System.out.println("螢幕對接介面卡,手機成功投影到螢幕!"); //第三種介面卡用法 System.out.println("-------------第三種介面卡------------"); VgaAdapter vgaAdapter = new VgaAdapter(); vgaAdapter.typec(); vgaAdapter.typec2vga();//介面卡將typec轉換成vga System.out.println("螢幕對接介面卡,手機成功投影到螢幕!"); } }
4.5 測試結果
圖5. 結果輸出圖
可以看到,得到的結果都一樣,但是三種介面卡的實現的方式卻不相同。
5 小結
5.1 介面卡模式在原始碼中的應用:
(1)JDK原始碼的IO模組用到,例如 java.io.InputStreamReader(InputStream)、java.io.OutputStreamWriter(OutputStream)。
(2)mybatis原始碼日誌模組用到物件介面卡模式。
5.1 介面卡模式將一個介面轉為另外一個介面。它有三種實現方式:
(1)當希望將一個類轉換為滿足另一個新介面的類時,可以使用類的介面卡模式,建立一個新類,繼承原有的類,實現新的介面即可,例如4.3.1。
(2) 當希望將一個物件轉換成滿足另一個新介面的物件時,可以建立一個Typec2Vga2 類,持有原類的一個例項,在Typec2Vga2 類的方法中,呼叫例項的方法就行,例如4.3.2物件的介面卡模式。
(3)當不希望實現一個介面中所有的方法時,可以建立一個抽象類Adapter ,實現所有方法,我們寫別的類的時候,繼承抽象類即可,例如4.3.3介面的介面卡模式。
6 我的其他JAVA設計模式