摘要:根據適配器類與適配者類的關系不同,適配器模式可分為對象適配器和類適配器兩種,在對象適配器模式中,適配器與適配者之間是關聯聚合關系在類適配器模式中,適配器與適配者之間是繼承或實現關系。
1、不同國家的插座是有區別的,如果我們去國外旅游,需要帶上國外的插頭轉換器,來能兼容國外的插座;
2、手機的耳機孔有圓頭和扁頭,如果扁頭的耳機孔想接圓頭的耳機就需要一個耳機的轉換器;
上述所說的轉換器,其實就是適配器;它是用來做兼容的;
適配器模式(Adapter Pattern):將一個接口轉換成客戶希望的另一個接口,使接口不兼容的那些類可以一起工作,其別名為包裝器(Wrapper)。適配器模式既可以作為類結構型模式,也可以作為對象結構型模式。
在適配器模式中,我們通過增加一個新的適配器類來解決接口不兼容的問題,使得原本沒有任何關系的類可以協同工作。
根據適配器類與適配者類的關系不同,適配器模式可分為對象適配器和類適配器兩種,在對象適配器模式中,適配器與適配者之間是關聯(聚合)關系;在類適配器模式中,適配器與適配者之間是繼承(或實現)關系。
Target(目標抽象類):目標抽象類定義客戶所需接口,可以是一個抽象類或接口,也可以是具體類。
Adapter(適配器類):適配器可以調用另一個接口,作為一個轉換器,對Adaptee和Target進行適配,適配器類是適配器模式的核心,在對象適配器中,它通過繼承Target并關聯一個Adaptee對象使二者產生聯系。
Adaptee(適配者類—適配接口):適配者即被適配的角色,它定義了一個已經存在的接口,這個接口需要適配,適配者類一般是一個具體類,包含了客戶希望使用的業務方法,在某些情況下可能沒有適配者類的源代碼。
缺省適配器模式(Default Adapter Pattern):當不需要實現一個接口所提供的所有方法時,可先設計一個抽象類實現該接口,并為接口中每個方法提供一個默認實現(空方法),那么該抽象類的子類可以選擇性地覆蓋父類的某些方法來實現需求,它適用于不想使用一個接口中的所有方法的情況,又稱為單接口適配器模式。
以生活中充電器為例,充電器本身相當于適配者 (Adapter),220V 交流電相當于被適配者,我們的目標(target) 想把220V交流電轉成5V直流電
要適配的類,即需要將220v電壓轉化為5v電壓
//中國的電壓220Vpublic class ChinaPower{ private final Integer outPut=220; public Integer getOutPut() { return outPut; }}
適配器接口,只負責定義轉化需要使用的業務邏輯方法,具體實現交由適配器類完成
//將電壓轉化為5v---適配接口public interface TransTo5V{ Integer transTo5V();}
適配器類,繼承了ChinaPower,并實現了適配器接口,負責實現講220v電壓轉化為5v的具體業務邏輯代碼實現
//適配器類---實現適配器接口public class ChinaAdapter extends ChinaPower implements TransTo5V{ //將220v電壓轉換為5v的 @Override public Integer transTo5V() { //獲得被適配類,即我們需要將220v電壓轉化為5v返回 Integer output=super.getOutPut(); //進行電壓轉換操作 return output/44; }}
Phone類,需要用到適配器進行兼容,這樣才可以充電
//手機需要5v的電壓進行充電public class Phone{ //通過適配器獲得5v的電壓 public void charging(ChinaAdapter chinaAdapter) { if(5==chinaAdapter.transTo5V()) { System.out.println("得到5v,充電中..."); } else { System.out.println("電壓過高,手機壓力過大"); } }}
充電測試
public class test{ @Test public void test() { Phone p=new Phone(); p.charging(new ChinaAdapter()); }}
還是以上面的例子為例,這一次適配器類不再繼承ChinaPower ,而是以聚合的方式來代替繼承,符合設計模式中的"合成復用原則";java是單繼承機制,這樣可以保留對象繼承權;
我們只需要修改適配器類即可:
//適配器類---實現適配器接口public class ChinaAdapter implements TransTo5V{ private ChinaPower chinaPower; //通過構造器,完成賦值 public ChinaAdapter(ChinaPower chinaPower) { this.chinaPower=chinaPower; } //將220v電壓轉換為5v的 @Override public Integer transTo5V() { //獲得被適配類,即我們需要將220v電壓轉化為5v返回 Integer output=chinaPower.getOutPut(); //進行電壓轉換操作 return output/44; }}
測試
public class test{ @Test public void test() { Phone p=new Phone(); p.charging(new ChinaAdapter(new ChinaPower())); }}
對象適配器和類適配器其實算是同一種思想,只不過實現方式不同。根據合成復用原則,使用組合替代繼承, 所以它解決了類適配器必須繼承被適配者的局限性問題;
定義一個適配器接口:
public interface InterfaceTest { public void m1(); public void m2(); public void m3(); public void m4();}
抽象類 AbsAdapter 將 InterfaceTest 的方法進行默認實現,當子類需要使用適配器接口中的某個方法,而不是全部方法時,就可以通過繼承抽象類,來完成對需要使用的特定方法重寫操作即可,無需實現適配器接口里面的全部方法
public abstract class AbsAdapter implements InterfaceTest { //默認實現 public void m1() {} public void m2() {} public void m3() {} public void m4() {}}
Client 調用接口,重寫適配器抽象類方法
public class Client { public static void main(String[] args) { AbsAdapter absAdapter = new AbsAdapter() { //只需要去覆蓋我們 需要使用 接口方法 @Override public void m1() { System.out.println("使用了m1的方法"); } }; absAdapter.m1(); }}
一個頂層接口Power
public interface Power{ Integer getOutPut();}
分支一: 中國的220v電壓
//中國的電壓220Vpublic class ChinaPower implements Power{ private final Integer outPut=220; @Override public Integer getOutPut() { return outPut; }}
分支二: 日本的110v電壓
//日本電壓110vpublic class JapenPower implements Power{ private final Integer output=110; @Override public Integer getOutPut() { return output; }}
失配器接口–DC5Adapter
//適配器接口public interface DC5Adapter{ boolean support(Power power); Integer transTo5V(Power power);}
適配器類—ChinaAdapter–只負責將220v電壓進行轉換的工作
//該適配器負責將中國的220v電壓轉化為5v的電壓public class ChinaAdapter implements DC5Adapter{ //當前適配器只負責將220v電壓轉化為5v的功能實現 private static Integer voltage=220; //判斷當前適配器能否勝任傳入power電壓的轉化職責 @Override public boolean support(Power power) { if(power.getOutPut().equals(voltage)) return true; return false; } //將220v電壓轉換為5v的 @Override public Integer transTo5V(Power power) { //獲得被適配類,即我們需要將220v電壓轉化為5v返回 Integer output=power.getOutPut(); //進行電壓轉換操作 return output/44; }}
適配器類—JapenAdapter–只負責將110v電壓進行轉換的工作
//該適配器負責將日本的110v電壓轉化為5v的電壓public class JapenAdapter implements DC5Adapter{ //當前適配器只負責將110v電壓轉化為5v的功能實現 private static Integer voltage=110; //判斷是否支持將日本110v電壓轉化為5v電壓的操作 @Override public boolean support(Power power) { if(power.getOutPut()==voltage) return true; return false; } //將110v電壓轉換為5v的 @Override public Integer transTo5V(Power power) { //獲得被適配類,即我們需要將110v電壓轉化為5v返回 Integer output=power.getOutPut(); //進行電壓轉換操作 return output/22; }}
//手機需要5v的電壓進行充電public class FindAdapter{ //存放所有適配器的set集合 private static final Set<DC5Adapter> DC5Adapters=new HashSet<>(); //通過靜態代碼塊進行初始化操作 static { DC5Adapters.add(new ChinaAdapter()); DC5Adapters.add(new JapenAdapter()); } // 根據電壓找合適的變壓器 public DC5Adapter getPowerAdapter(Power power) { DC5Adapter dc5Adapter=null; for(DC5Adapter da:DC5Adapters) { //如果遍歷到當前電壓合適的變壓器就直接退出遍歷 if(da.support(power)) { dc5Adapter=da; break; } } //如果遍歷完所有的變壓器都沒有找到合適的,就拋出異常 if(dc5Adapter==null) { throw new IllegalArgumentException("未能找到合適的變壓器"); } //返回找到的合適的變壓器 return dc5Adapter; }}
public class test{ @Test public void test() { //找尋合適的變壓器是第一步 FindAdapter fa=new FindAdapter(); //找尋可以將220v轉化為5v的變壓器,即適配器 DC5Adapter adapter = fa.getPowerAdapter(new ChinaPower()); //輸出當前變壓器轉化之后的電壓 System.out.println(adapter.transTo5V(new ChinaPower())); }}
具體來說,類適配器模式還有如下優點:
SpringMVM 中的 HandlerAdapter(上圖的第4步), 就使用了適配器模式;
Spring MVC中的適配器模式主要用于執行目標 Controller
中的請求處理方法。
在Spring MVC中,DispatcherServlet
作為用戶,HandlerAdapter
作為期望接口(適配器接口),具體的適配器實現類用于對目標類進行適配,Controller
作為需要適配的類。
為什么要在 Spring MVC 中使用適配器模式?Spring MVC 中的 Controller
種類眾多,不同類型的 Controller
通過不同的方法來對請求進行處理。如果不利用適配器模式的話,DispatcherServlet
直接獲取對應類型的 Controller
,需要的自行來判斷,像下面這段代碼一樣:
if(mappedHandler.getHandler() instanceof MultiActionController){ ((MultiActionController)mappedHandler.getHandler()).xxx }else if(mappedHandler.getHandler() instanceof XXX){ ... }else if(...){ ... }
這樣假設如果我們增加一個 HardController
,就要在代碼中加入一行 if(mappedHandler.getHandler() instanceof HardController)
,這種形式就使得程序難以維護,也違反了設計模式中的開閉原則 – 對擴展開放,對修改關閉。
我們來看看源碼,首先是適配器接口 HandlerAdapter
//適配器接口public interface HandlerAdapter { //判斷當前的controller請求是否能被當前的適配器類處理 boolean supports(Object var1); //只有當支持處理當前請求后,才會執行下面的處理請求方法,返回一個ModelAndView對象 ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception; long getLastModified(HttpServletRequest var1, Object var2);}
現該接口的適配器每一個 Controller
都有一個適配器與之對應,這樣的話,每自定義一個 Controller
需要定義一個實現 HandlerAdapter
的適配器。
springmvc 中提供的 Controller
實現類有如下:
springmvc 中提供的 HandlerAdapter
實現類如下
HttpRequestHandlerAdapter 這個適配器代碼如下:
//不同的適配器類實現不同的功能//當前的HttpRequestHandlerAdapter 適配器類,只負責處理關于HttpRequest相關的請求public class HttpRequestHandlerAdapter implements HandlerAdapter { public HttpRequestHandlerAdapter() { } //判斷當前的controller請求是否是HttpRequestHandler類型的 //當前適配器只支持處理當前類型的handler public boolean supports(Object handler) { return handler instanceof HttpRequestHandler; } //如果驗證支持,會調用下面這個方法進行具體邏輯處理 public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //先進行強制類型轉換,轉換為指定的handler類型,然后就可以調用該類型處理對應請求的方法了 //調用HttpRequestHandler的handleRequest處理對應的請求 ((HttpRequestHandler)handler).handleRequest(request, response); return null; } public long getLastModified(HttpServletRequest request, Object handler) { return handler instanceof LastModified ? ((LastModified)handler).getLastModified(request) : -1L; }}
當Spring容器啟動后,會將所有定義好的適配器對象存放在一個List集合中,當一個請求來臨時,DispatcherServlet
會通過 handler
的類型找到對應適配器,并將該適配器對象返回給用戶,然后就可以統一通過適配器的 hanle()
方法來調用 Controller
中的用于處理請求的方法。
public class DispatcherServlet extends FrameworkServlet {//用于存放所有HandlerAdapter適配器類的list集合 private List<HandlerAdapter> handlerAdapters; //初始化handlerAdapters private void initHandlerAdapters(ApplicationContext context) { //..省略... } // 遍歷所有的 HandlerAdapters,通過 supports 判斷找到匹配的適配器 protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { for (HandlerAdapter ha : this.handlerAdapters) { if (logger.isTraceEnabled()) { logger.trace("Testing handler adapter [" + ha + "]"); } if (ha.supports(handler)) { return ha; } } } // 分發請求,請求需要找到匹配的適配器來處理 protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request;
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/118905.html
摘要:原文地址設計模式十適配器模式在設計模式七設計模式分類中我們提到過結構設計模式,結構設計模式專注于設計對象和實例的構建組合過程。適配器模式在不修改現有代碼的基礎上,保留了架構。 原文地址:PHP設計模式(十):適配器模式 Introduction 在PHP設計模式(七):設計模式分類中我們提到過結構設計模式(Structural patterns),結構設計模式專注于設計對象(Objec...
摘要:本文參考于設計模式課程設計模式之適配器模式設計模式是一套被反復使用的多數人知曉的經過分類編目的代碼設計經驗的總結。第一個設計模式是適配器模式??偟膩碚f適配器就是的模式,與修飾模式直接無感使用不同,適配器模式使用對象變為。 本文參考于:設計模式課程設計模式之適配器模式 設計模式是一套被反復使用的、多數人知曉的、經過分類編目的、代碼設計經驗的總結。使用設計模式是為了重用代碼、讓代碼更容易被...
摘要:與其它模式的異同適配器模式不會改變原有接口,這一點與裝飾者模式和代理模式類似。代理模式適配器模式與代理模式最相似,同樣都是創建一個新對象包裝一次,實現對本體的調用。外觀模式外觀模式與適配器模式最大的區別,是定義了一個新的接口。 showImg(https://segmentfault.com/img/bVbul8d?w=800&h=600); 適配器模式:將一個類(對象)的接口(方法或...
摘要:適配器模式橋接模式過濾器模式組合模式裝飾器模式外觀模式享元模式代理模式行為型模式這些設計模式特別關注對象之間的通信。對象適配器另外一種適配器模式是對象適配器,它不是使用多繼承或繼承再實現的方式,而是使用直接關聯,或者稱為委托的方式。 設計模式匯總 創建型模式 這些設計模式提供了一種在創建對象的同時隱藏創建邏輯的方式,而不是使用新的運算符直接實例化對象。這使得程序在判斷針對某個給定實例需...
閱讀 2689·2021-10-12 10:12
閱讀 2335·2021-09-02 15:41
閱讀 2561·2019-08-30 15:55
閱讀 1399·2019-08-30 13:05
閱讀 2430·2019-08-29 11:21
閱讀 3534·2019-08-28 17:53
閱讀 3022·2019-08-26 13:39
閱讀 800·2019-08-26 11:50