配接器模式
1 現實生活中的配接器例子
泰國插座用的是兩孔的(歐標),可以買個多功能轉換插頭 (配接器) ,這樣就可以使用了,

2 基本介紹
1) 配接器模式(Adapter Pattern)將某個類的介面轉換成客戶端期望的另一個介面表示,主的目的是兼容性,讓原本因介面不匹配不能一起作業的兩個類可以協同作業,其別名為包裝器(Wrapper)
2) 配接器模式屬于結構型模式
3) 主要分為三類:類配接器模式、物件配接器模式、介面配接器模式
3 作業原理
1) 配接器模式:將一個類的介面轉換成另一種介面.讓原本介面不兼容的類可以兼容
2) 從用戶的角度看不到被適配者,是解耦的
3) 用戶呼叫配接器轉化出來的目標介面方法,配接器再呼叫被適配者的相關介面方法
用戶收到反饋結果,感覺只是和目標介面互動,如圖

4 類配接器模式
4.1 類配接器模式介紹
基本介紹:Adapter 類,通過繼承 src 類,實作 dst 類介面,完成 src->dst 的適配,
4.2 類配接器模式應用實體
1) 應用實體說明
以生活中充電器的例子來講解配接器,充電器本身相當于 Adapter,220V 交流電相當于 src (即被適配者),我們的目 dst(即 目標)是 5V 直流電
2) 思路分析(類圖)

Voltage220V類
package com.lin.adapter.classadapter; public class Voltage220V{ public int output220V() { int src = https://www.cnblogs.com/linzm14/p/220; System.out.println("電壓:" + src); return src; } }
IVoltage5V介面
package com.lin.adapter.classadapter; public interface IVoltage5V { int output5V(); }
VoltageAdapter類
package com.lin.adapter.classadapter; public class VoltageAdapter extends Voltage220V implements IVoltage5V{ @Override public int output5V() { int srcV = output220V(); int dstV = srcV / 44; return dstV; } }
Phone類
package com.lin.adapter.classadapter; public class Phone { public void charging(IVoltage5V iVoltage5V) { if(iVoltage5V.output5V() == 5) { System.out.println("電壓為5伏可以充電!"); } else if(iVoltage5V.output5V() > 5){ System.out.println("電壓不符!無法充電!"); } } }
Client類
package com.lin.adapter.classadapter; public class Client { public static void main(String[] args) { System.out.println("配接器模式"); Phone phone = new Phone(); phone.charging(new VoltageAdapter()); } }
4.3 類配接器模式注意事項和細節
1) Java 是單繼承機制,所以類配接器需要繼承 src 類這一點算是一個缺點, 因為這要求 dst 必須是介面,有一定局限性;
2) src 類的方法在 Adapter 中都會暴露出來,也增加了使用的成本,
由于其繼承了 src 類,所以它可以根據需求重寫 src 類的方法,使得 Adapter 的靈活性增強了
5 物件配接器模式
5.1 物件配接器模式介紹
1) 基本思路和類的配接器模式相同,只是將 Adapter 類作修改,不是繼承 src 類,而是持有 src 類的實體,以解決兼容性的問題, 即:持有 src 類,實作 dst 類介面,完成 src->dst 的適配
2) 根據“合成復用原則”,在系統中盡量使用關聯關系(聚合)來替代繼承關系,
3) 物件配接器模式是配接器模式常用的一種
5.2 物件配接器模式應用實體
1) 應用實體說明
以生活中充電器的例子來講解配接器,充電器本身相當于 Adapter,220V 交流電相當于 src (即被適配者),我們的目 dst(即目標)是 5V 直流電,使用物件配接器模式完成,
2) 思路分析(類圖):只需修改配接器即可, 如下:

其中有兩個類代碼不同,其他三個類代碼和上面一樣
VoltageAdapter類
package com.lin.adapter.objectdapter; public class VoltageAdapter implements IVoltage5V{ private Voltage220V voltage220V = null; public VoltageAdapter(Voltage220V voltage220v) { this.voltage220V = voltage220v; } public int output5V() { int dstV = 0; if(voltage220V != null) { int srcV = voltage220V.output220V(); dstV = srcV / 44; } return dstV; } }
Client類
package com.lin.adapter.objectdapter; public class Client { public static void main(String[] args) { System.out.println("配接器模式"); Phone phone = new Phone(); phone.charging(new VoltageAdapter(new Voltage220V())); } }
5.3 物件配接器模式注意事項和細節
1) 物件配接器和類配接器其實算是同一種思想,只不過實作方式不同,
根據合成復用原則,使用組合替代繼承, 所以它解決了類配接器必須繼承 src 的局限性問題,也不再要求 dst必須是介面,
2) 使用成本更低,更靈活,
6 介面配接器模式
6.1 介面配接器模式介紹
1) 一些書籍稱為:配接器模式(Default Adapter Pattern)或預設配接器模式,
2) 核心思路:當不需要全部實作介面提供的方法時,可先設計一個抽象類實作介面,并為該介面中每個方法提供一個默認實作(空方法),那么該抽象類的子類可有選擇地覆寫父類的某些方法來實作需求
3) 適用于一個介面不想使用其所有的方法的情況,
6.2 介面配接器模式應用實體
1) Android 中的屬性影片 ValueAnimator 類可以通過 addListener(AnimatorListener listener)方法添加監聽器, 那么常規寫法如右:
2)有時候我們不想實作 Animator.AnimatorListener 介面的全部方法,我們只想監聽 onAnimationStart,我們會如下寫

3) AnimatorListenerAdapter 類,就是一個介面配接器,代碼如右圖:它空實作了Animator.AnimatorListener 類(src)的所有方法.
4) AnimatorListener 是一個介面.

5) 程式里的匿名內部類就是 Listener 具體實作類

6) 案例說明

AbstractAdapter類
package com.lin.adapter.interfacedapter; public abstract class AbstractAdapter implements IntergaceTest{ @Override public void method1() { // TODO Auto-generated method stub } @Override public void method2() { // TODO Auto-generated method stub } @Override public void method3() { // TODO Auto-generated method stub } @Override public void method4() { // TODO Auto-generated method stub } @Override public void method5() { // TODO Auto-generated method stub } }
InterfaceTest介面
package com.lin.adapter.interfacedapter; interface IntergaceTest{ void method1(); void method2(); void method3(); void method4(); void method5(); }
Client類
package com.lin.adapter.interfacedapter; public class Client { public static void main(String[] args) { new AbstractAdapter() { @Override public void method1() { // TODO Auto-generated method stub super.method1(); } }; } }
7 配接器模式在 SpringMVC 框架應用的原始碼剖析
1) SpringMvc 中的 HandlerAdapter, 就使用了配接器模式
2) SpringMVC 處理請求的流程回顧
3) 使用 HandlerAdapter 的原因分析:
可以看到處理器的型別不同,有多重實作方式,那么呼叫方式就不是確定的,如果需要直接呼叫 Controller 方法,需要呼叫的時候就得不斷是使用 if else 來進行判斷是哪一種子類然后執行,那么如果后面要擴展 Controller, 就得修改原來的代碼,這樣違背了 OCP 原則,
4) 代碼分析

5)動手寫 SpringMVC 通過配接器設計模式獲取到對應的 Controller 的原始碼


Controller類
package com.lin.adapter.interfacedapter.springMVC; public interface Controller { } class HttpController implements Controller{ public void doHttpHandler() { System.out.println("http..."); } } class SimpleController implements Controller{ public void doSimpleHandler() { System.out.println("simple..."); } } class AnnotationController implements Controller{ public void doAnnotationHandler() { System.out.println("annotation..."); } }
HandlerAdapter類
package com.lin.adapter.interfacedapter.springMVC; public interface HandlerAdapter { boolean supports(Object handler); void handle(Object handler); } // 多種配接器類 class SimpleHandlerAdapter implements HandlerAdapter{ @Override public boolean supports(Object handler) { // TODO Auto-generated method stub return (handler instanceof SimpleController); } @Override public void handle(Object handler) { // TODO Auto-generated method stub ((SimpleController)handler).doSimpleHandler(); } } class HttpHandlerAdapter implements HandlerAdapter{ @Override public boolean supports(Object handler) { // TODO Auto-generated method stub return (handler instanceof HttpController); } @Override public void handle(Object handler) { // TODO Auto-generated method stub ((HttpController)handler).doHttpHandler(); } } class AnnotationHandlerAdapter implements HandlerAdapter{ @Override public boolean supports(Object handler) { // TODO Auto-generated method stub return (handler instanceof AnnotationController); } @Override public void handle(Object handler) { // TODO Auto-generated method stub ((AnnotationController)handler).doAnnotationHandler(); } }
DispatchServlet類
package com.lin.adapter.interfacedapter.springMVC; import java.util.ArrayList; import java.util.List; public class DispatchServlet { public static List<HandlerAdapter> handlerAdapters = new ArrayList<HandlerAdapter>(); public DispatchServlet() { handlerAdapters.add(new AnnotationHandlerAdapter()); handlerAdapters.add(new HttpHandlerAdapter()); handlerAdapters.add(new SimpleHandlerAdapter()); } public void doDispatch() { /* * 此處模擬SpringMVC從request取handler的物件 * 配接器可以獲取到control * */ AnnotationController annotationController = new AnnotationController(); HandlerAdapter handlerAdapter = getHandler(annotationController); handlerAdapter.handle(annotationController); } public HandlerAdapter getHandler(Controller controller) { for (HandlerAdapter handlerAdapter : handlerAdapters) { if(handlerAdapter.supports(controller)) { return handlerAdapter; } } return null; } }
Client類
package com.lin.adapter.interfacedapter.springMVC; public class Client { public static void main(String[] args) { new DispatchServlet().doDispatch(); } }
8 配接器模式的注意事項和細節
1) 三種命名方式,是根據 src 是以怎樣的形式給到 Adapter(在 Adapter 里的形式)來命名的,
2) 類配接器:以類給到,在 Adapter 里,就是將 src 當做類,繼承
物件配接器:以物件給到,在 Adapter 里,將 src 作為一個物件,持有介面配接器:以介面給到,在 Adapter 里,將 src 作為一個介面,實作
3) Adapter 模式最大的作用還是將原本不兼容的介面融合在一起作業,
4) 實際開發中,實作起來不拘泥于我們講解的三種經典形式
僅供參考,有錯誤還請指出!
有什么想法,評論區留言,互相指教指教,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/256609.html
標籤:Java
