1 初步認識 適配器模式的定義 將一個類的介面轉成客戶期望的另外一個介面。適配器模式使得原本由於介面不匹配而不能一起工作的那些類可以一起工作。 大白話 適配器模式就像旅行插座轉換器(圖1)、Type-c轉VGA轉介面(圖4)一樣。 圖1. 圖片來源網路 圖2. 圖片來源網路 去過香港迪拜等的同學都知 ...
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設計模式