基本需求:
- 將一個220V的電壓輸出成5V的電壓,其中220V電壓為被適配者,變壓器為介面卡,5v電壓為適配目標
基本介紹:
- 介面卡模式屬於結構型模式,將某個類的介面轉換成客戶端期望的另一個介面表示,主的目的是相容性,讓原本因介面不匹配不能一起工作的兩個類可以協同工作。其別名為包裝器(Wrapper) 分為類介面卡模式,物件介面卡模式,介面介面卡模式
- 使用者的角度看不到被適配者,是解耦的,使用者呼叫介面卡轉化出來的目標介面方法,介面卡再呼叫被適配者的相關介面方法
類介面卡模式:
-
Adapter 類,通過繼承 src 類,實現 dst 類介面,完成 src->dst 的適配
-
UML類圖
-
程式碼實現
-
public class Voltage220V { // 被適配類 public int output220V() { System.out.println("輸出220V電壓"); return 220; } } public interface Voltage5V { // 使用者需要使用的介面 int output5V(); } public class VoltageAdapter extends Voltage220V implements Voltage5V { // 適配方法(通過實現使用者使用的介面將配適配的類轉換成使用者所需要的) @Override public int output5V() { int output = output220V() / 44; System.out.println("適配出5V電壓"); return output; } } public class Phone { // 使用介面 public void charging(Voltage5V voltage5V) { voltage5V.output5V(); } } // client呼叫 public static void main(String[] args) { Phone phone = new Phone(); // 使用者只關心介面 不需要關心被適配者 phone.charging(new VoltageAdapter()); }
-
-
注意事項
- Java是單繼承機制,所以類介面卡需要繼承src類這一點算是一個缺點, 因為這要求dst必須是介面,有一定侷限性
- src類的方法在Adapter中都會暴露出來,也增加了使用的成本
- 由於其繼承了src類,所以它可以根據需求重寫src類的方法,使得Adapter的靈活性增強了
物件介面卡模式:
-
基本思路和類的介面卡模式相同,只是將Adapter類作修改,不是繼承src類,而是持有src類的例項,以解決相容性的問題。即:持有src類,實現dst類介面,完成 src->dst的適配,將被適配者類的物件聚合組合到介面卡類中
-
根據“ 合成複用原則”,在系統中儘量使用 關聯關係(聚合)來替代繼承關係
-
UML類圖
-
程式碼實現
-
// 只需要對類介面卡模式中的介面卡類進行修改即可 public class VoltageAdapter implements Voltage5V { // 直接將被適配類物件聚合到介面卡中,免去了繼承 // 根據“ 合成複用原則”,在系統中儘量使用 關聯關係(聚合)來替代繼承關係 private Voltage220V voltage220V; public VoltageAdapter(Voltage220V voltage220V) { this.voltage220V = voltage220V; } // 適配方法 @Override public int output5V() { int output = voltage220V.output220V() / 44; System.out.println("適配出5V電壓"); return output; } }
-
-
注意事項
- 物件介面卡和類介面卡其實算是同一種思想,只不過實現方式不同。根據合成複用原則,使用組合替代繼承,所以它解決了類介面卡必須繼承src的侷限性問題,也不再要求 dst必須是介面
- 使用成本更低,更靈活
介面介面卡模式:
-
核心思路:當不需要全部實現介面提供的方法時,可先設計一個抽象類實現介面,併為該介面中每個方法提供一個預設實現(空方法),那麼該抽象類的子類可有選擇地覆蓋父類的某些方法來實現需求
-
適用於一個介面不想使用其所有的方法的情況
-
UML類圖
-
程式碼實現
-
public class Voltage220V { // 被適配類 public int output220V() { System.out.println("輸出220V電壓"); return 220; } } public interface OutputVoltage { // 該介面提供多種方法,介面卡抽象類對該介面的全部方法進行空實現 // 使用時使用者只重寫他們關心的那個方法即可,不需要關心其他的方法 int output5V(); int output10V(); int output220V(); } public abstract class VoltageAdapter implements OutputVoltage { // 聚合被適配類 protected Voltage220V voltage220V; public VoltageAdapter(Voltage220V voltage220V) { this.voltage220V = voltage220V; } // 對介面中的所有適配方法進行空實現 @Override public int output5V() { return 0; } @Override public int output10V() { return 0; } @Override public int output220V() { return 0; } } public class Client { public static void main(String[] args) { VoltageAdapter voltageAdapter = new VoltageAdapter(new Voltage220V()) { // 使用時使用者只重寫他們關心的那個方法即可,不需要關心其他的方法 @Override public int output5V() { int i = super.voltage220V.output220V() / 44; System.out.println("適配出5V電壓"); return i; } }; voltageAdapter.output5V(); } }
-
springmvc原始碼:
-
springMVC中DispatchServlet中的doDispatch方法 就用到了介面卡模式,通過Handler物件適配出了HandlerAdapter物件,通過HandlerAdapter執行Handler物件中的方法
-
DispatcherServlet -> HandlerMapping(得到處理器鏈) -> HandlerAdapter(處理器介面卡) -> Handler(處理器) -> ViewAndResolver(檢視解析器) -> 模板等返回給瀏覽器
-
簡單實現DispatcherServlet中的介面卡
-
UML類圖
-
程式碼實現
-
// 處理器介面卡介面及實現類 public interface MyHandlerAdapter { // 處理器介面卡 判斷是那種介面卡 boolean support(Object object); // 通過介面卡執行處理器中的方法 void handler(Object object); } class MyHttpRequestHandlerAdapter implements MyHandlerAdapter{ @Override public boolean support(Object object) { return object instanceof MyHttpRequestHandler; } @Override public void handler(Object object) { MyHttpRequestHandler myHttpRequestHandler = (MyHttpRequestHandler) object; myHttpRequestHandler.doHttpRequest(); } } class MySimpleControllerHandlerAdapter implements MyHandlerAdapter{ @Override public boolean support(Object object) { return object instanceof MySimpleControllerHandler; } @Override public void handler(Object object) { MySimpleControllerHandler mySimpleControllerHandler = (MySimpleControllerHandler) object; mySimpleControllerHandler.doSimpleController(); } } class MySimpleServletHandlerAdapter implements MyHandlerAdapter{ @Override public boolean support(Object object) { return object instanceof MySimpleServletHandlerAdapter; } @Override public void handler(Object object) { MySimpleServletHandler mySimpleServletHandler = (MySimpleServletHandler) object; mySimpleServletHandler.doSimpleServlet(); } }
-
// 處理器介面及實現類 public interface MyHandler { // 處理器介面 } class MyHttpRequestHandler implements MyHandler { public void doHttpRequest() { System.out.println("doHttpRequest..."); } } class MySimpleControllerHandler implements MyHandler { public void doSimpleController() { System.out.println("doSimpleController..."); } } class MySimpleServletHandler implements MyHandler { public void doSimpleServlet() { System.out.println("doSimpleServlet..."); } }
-
public class MyDispatcherServlet { // 進行spring mvc中DispatcherServlet的簡單實現 private static List<MyHandlerAdapter> myHandlerAdapters = new ArrayList<>(); public MyDispatcherServlet() { myHandlerAdapters.add(new MyHttpRequestHandlerAdapter()); myHandlerAdapters.add(new MySimpleControllerHandlerAdapter()); myHandlerAdapters.add(new MySimpleServletHandlerAdapter()); } public void doDispatcher(String request) { // 實際執行流程 DispatcherServlet -> HandlerMapping(得到處理器鏈) -> HandlerAdapter(處理器介面卡) -> Handler(處理器) -> ViewAndResolver(檢視解析器) -> 模板等返回 // 實際 通過HttpServletRequest物件獲取的Handler物件 此處簡化即可 MyHttpRequestHandler myHttpRequestHandler = new MyHttpRequestHandler(); MyHandlerAdapter handlerAdapter = getHandlerAdapter(myHttpRequestHandler); // 通過獲取到的HandlerAdapter物件來執行指定種類Handler的方法 // 不同的HandlerAdapter執行Handler的方法的方式不一樣 // 感覺相當於將Handle物件分成了多類,每類通過自己的HandlerAdapter執行Handler物件中的處理方法,這樣每類的執行方式都一樣 handlerAdapter.handler(myHttpRequestHandler); } /** * 通過Handler獲取對應的HandlerAdapter進行適配 * @param myHandler * @return */ public MyHandlerAdapter getHandlerAdapter(MyHandler myHandler) { if (null != this.myHandlerAdapters) { for (MyHandlerAdapter myHandlerAdapter : myHandlerAdapters) { if (myHandlerAdapter.support(myHandler)) { return myHandlerAdapter; } } } throw new RuntimeException("該Handler沒有對應的HandlerAdapter"); } public static void main(String[] args) { MyDispatcherServlet myDispatcherServlet = new MyDispatcherServlet(); myDispatcherServlet.doDispatcher("url"); } }
-
-
注意事項:
- 三種命名方式,是根據src是以怎樣的形式給到Adapter(在 Adapter 裡的形式)來命名的
- 類介面卡:以類給到,在Adapter裡,就是將src當做類,繼承
- 物件介面卡:以物件給到,在Adapter裡,將src作為一個物件,持有
- 介面介面卡:以介面給到,在Adapter裡,將src作為一個介面,實現
- Adapter模式最大的作用還是將原本不相容的介面融合在一起工作
- 實際開發中,實現起來不拘泥於我們講解的三種經典形式