將一個類的接口轉換成客戶指望的另外一個接口,使得本來的接口不兼容的類能夠一塊兒工做,結構型設計模式.spring
適配器模式不是設計階段考慮使用的設計模式,隨着軟件維護因爲接口不相同下的解決方案.設計模式
《Head First 設計模式》中提到適配器分爲兩類:對象適配器,類適配器,此外還有一種==接口適配器==.app
對象適配器:使用組合的方式,假設咱們須要調用的目標是接口,可是現有的類/接口 和 目標接口不兼容,咱們須要一個==適配器==實現目標接口,而且持有 被適配接口/類 對象。框架
類適配器:類適配器在《Head First 設計模式》中原來指多繼承,可是java中,指採用繼承的方式,實現目標接口同時繼承被適配類,這樣繼續使用接口的形式調用適配器,從而無感知達到目的。 可是若是被適配類不可知因素過多,使用起來可能 繼承效果不如組合來得方便,個人理解假如被適配的類都是經過Spring
實例化的,那就有點麻煩了.ide
接口適配器:接口適配器區別於前面兩種,假如一個接口很龐大,咱們每次寫一個實現類都須要實現全部方法,而後只改寫咱們用到一兩個方法,那代碼看起來也會很臃腫,因而就有了接口適配器。 使用抽象類實現接口的全部方法,抽象類實現的接口方法所有是空方法,當新須要一個子類時候,繼承抽象類而且只重寫特定的方法便可。源碼分析
前幾天去了香港,住宿一晚發現,香港電壓和內陸是同樣的220V,50HZ,可是咱們不能直接在插頭插上充電線來給手機充電,香港法律規定室內電器插頭都是英式的方腳三柱插頭,內陸的插頭都是兩腳插頭,像手機充電線插頭都是兩個平行的腳,這時候使用酒店提供的轉換器就能夠正常使用充電線了,轉換器就像是適配器。這就是對象適配器的一個小例子,內陸標準的充電插頭規範(雙平行腳)就是咱們的目標接口,可是在香港室內都沒有這種提供使用的雙腳的充電插槽, 轉換器就是適配器,實現了國內插頭標準,由於它有 雙腳插槽,同時它還組合的 三角的充電插槽,無縫銜接.測試
//國內常見插頭接口規範 public interface DoublePin { void chargeForDoublePin(); } //適配器 public class PluginAdaptor implements DoublePin { private TripplePin tripplePin; public PluginAdaptor(final TripplePin tripplePin) { this.tripplePin = tripplePin; } @Override public void chargeForDoublePin() { tripplePin.chargeForThreePinOnly(); } } //香港以及之外的插頭規範 public class TripplePin { void chargeForThreePinOnly(){ System.out.println("充電中......"); } }
測試類PersonTests
this
public class PersonTests { public static void main(String[] args) { TripplePin hotelPlugin = new TripplePin(); DoublePin myChargeLine=new PluginAdaptor(hotelPlugin); myChargeLine.chargeForDoublePin(); } }
講解:適配器的目的至關於中間人,中間人確定要知道有兩方信息吧,對象適配器特徵:實現目標接口,持有另一方聯繫;設計
類適配器的例子
public class PluginAdaptor2 extends TripplePin implements DoublePin { @Override public void chargeForDoublePin() { chargeForThreePinOnly(); } }
講解:上面適配器的代碼稍做改動就是類適配器的例子, 不一樣之處就是採用繼承的方式做爲中間人,若是說 酒店轉換頭是組合的方式, 那繼承就比如 把方腳三柱插頭和轉換頭 包裹嚴實起來,只留個 雙腳的插槽暴露出來, 咱們可能感知下來:噢,香港和國內充電沒有區別,充電線帶過去同樣使用。
接口適配器的例子
java.awt
包中的WindowListener
接口定義了幾個 窗口的監聽事件,WindowAdapter
實現了接口,可是方法全都是空實現的,若是咱們須要關閉窗口時作額外處理,徹底一個匿名內部類而且重寫windowClosed
方法便可,代碼簡潔且效果同樣,(之前寫awt就沒搞明白windowClosing、windowClosed
區別是啥)
提升類的透明性以及複用, 低耦合,有利於程序擴展;符合開閉
如下是第一次讀Spring
源碼以後對於適配器模式
的理解。Spring中有不少Adapter
爲後綴的類,上面幾種形式的適配器很常見對象適配器ConverterAdapter
,接口適配器InstantiationAwareBeanPostProcessorAdapter
、HandlerInterceptorAdapter
,固然這些適配器每一個做用不相同須要結合源碼分析,這裏就不記錄了,至於==HandlerAdapter==、==AvisorAdapter==我感受不像是適配器模式,可是是否使用了什麼適配器還不太清楚.
==HandlerAdapter== 理解:名稱叫處理器適配器,在SpringMvc中的做用呢找到那個 HandlerAdapter , 而後就是 處理請求 。 我以爲更像是一種 適配 , 而不是適配器模式 ,也有人 說這更像命令模式,。 前面記錄的適配器模式 是將一個接口轉換爲 另外一個不兼容的接口,供客戶端調用; 先說沒有==HandlerAdapter==的話該是怎麼處理:
獲得mapperHandler.getHandler
,以後判斷他是個HttpRequestHandler
仍是HandlerMethod
等等, 進行大量IF ELSE 的邏輯處理,若是咱們在框架基礎上修改就須要改動源碼,不符合開閉原則。 如今就是將 全部的 HandlerAdapter
實現類放到集合中,調support(handler)
來判斷是否支持,以後僅僅用這個HandlerAdapter
去反射執行控制器的方法;
糾結了很久, 換個角度想 個人目標是調用這個 處理器的方法,咱們假設存在這樣一個接口unamed,這個接口呢用來動態判斷處理器類型而且反射調用;而另外一個不兼容的類就是HandlerAdapter
的各類實現類(好比SimpleServletHandlerAdapter 咱們徹底能夠寫個任意名字方法調用 handle.service(request,response); ) ,如今須要將這個unamed
接口和各個 不兼容的類實現適配, 我會寫個類去實現 unamed接口,而後實現handle方法, 可是組合的對象變成 HandlerAdapter
,而且HandlerAdapter是在每次調用這個接口實現類的handle方法以前去動態初始化.
下面這個看起來更是 適配器模式了吧 , 可是下面的代碼徹底不必,看起來累贅並且徹底不必。
public interface Unamed { ModelAndView handle1(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception; } public class UnamedImpl implements Unamed{ private HandlerAdapter ha; @Override public ModelAndView handle1(final HttpServletRequest request, final HttpServletResponse response, final Object handler) throws Exception { ha=getHandler(); return ha.handle(request,response,handler); } private HandlerAdapter getHandler() { //略 return null; } }
我好不容易說服了本身HandlerAdapter
是適配器模式,若是你能說服我有理有據,歡迎評論告訴我,這塊確實糾結了很久!