定義:將一個系統的接口轉換成另一種形式,從而使原來不能直接調用的接口變得能夠調用。數據庫
適配器模式涉及3個角色: 1.源(Adaptee):須要被適配的對象或類型,至關於插頭。 2.適配器(Adapter):鏈接目標和源的中間對象,至關於插頭轉換器。 3.目標(Target):期待獲得的目標,至關於插座。 適配器模式包括3種形式:類適配器模式、對象適配器模式、接口適配器模式(或又稱做缺省適配器模式)。
一、新老版本接口的兼容 二、Mybatis多種日誌框架的整合
1.對象適配器(組合模式) 2.類適配器(繼承模式)
好比早期的時候V1版本訂單接口的入參爲Map類型,隨着業務的更新和迭代在V2版本的時候該訂單接口的入參須要支持List的類型? 請問不改變的該接口代碼的狀況下,如何支持List類型。apache
1.源(Adaptee):須要被適配的對象或類型,至關於插頭。設計模式
public void froOrderMap(Map map) { for (int i = 0; i < map.size(); i++) { // 使用I做爲MapKey獲取數據 String value = (String) map.get(i); System.out.println("value:" + value); } }
2.目標(Target):期待獲得的目標,至關於插座。框架
public interface List<E> extends Collection<E> { ...... int size(); E get(int index); E set(int index, E element); }
3.適配器(Adapter):鏈接目標和源的中間對象,至關於插頭轉換器ide
public class ListAdapter extends HashMap { private List list; public ListAdapter(List list) { this.list = list; } @Override public int size() { return list.size(); } @Override public Object get(Object key) { return list.get(Integer.valueOf(key.toString()).intValue()); } }
測試運行效果源碼分析
public class Test { public static void main(String[] args) { // 1.獲取集合類型用戶 List member = new MemberService().getMember(); //new OrderService().froOrderMap(member); ListAdapter listAdapter = new ListAdapter(member); new OrderService().froOrderMap(listAdapter); } }
好比設計一個日誌收集系統,可能會考慮文件寫入、也可能考慮寫入MQ、也可能考慮寫入數據庫等。測試
定義基本實體類this
@Data public class LogBean { /** * 日誌ID */ private String logId; /** * 日誌內容 */ private String logText; }
1.源目標接口spa
public interface LogWriteFileService { /** * 將日誌寫入到文件中 */ void logWriteFile(); /** * 從本地文件中讀取日誌 * * @return */ List<LogBean> readLogFile(); }
1.源目標接口實現類.net
public class LogWriteFileServiceImpl implements LogWriteFileService { @Override public void logWriteFile() { System.out.println(">>>將日誌寫入文件中..."); } @Override public List<LogBean> readLogFile() { LogBean log1 = new LogBean(); log1.setLogId("0001"); log1.setLogText("Tomcat啓動成功.."); LogBean log2 = new LogBean(); log2.setLogId("0002"); log2.setLogText("Jetty啓動成功.."); List<LogBean> listArrayList = new ArrayList<LogBean>(); listArrayList.add(log1); listArrayList.add(log2); return listArrayList; } }
2.目標接口
public interface LogWriteDbService { /** * 將日誌寫入到數據庫中 */ public void writeDbFile(LogBean logBean); }
2.適配器
//LogAdapter :適配器 //LogWriteDbService:目標 public class LogAdapter implements LogWriteDbService { //源接口 private LogWriteFileService logWriteFileService; public LogAdapter(LogWriteFileService logWriteFileService) { this.logWriteFileService = logWriteFileService; } @Override public void writeDbFile(LogBean logBean) { // 1.從文件中讀取日誌文件 List<LogBean> logBeans = logWriteFileService.readLogFile(); //目標 // 2.寫入到數據庫中 logBeans.add(logBean); System.out.println(">>>將數據寫入到數據庫中.."); // 3.寫入到本地文件中 logWriteFileService.logWriteFile(); } }
適配器模式的優勢 更好的複用性 系統須要使用現有的類,而此類的接口不符合系統的須要。那麼經過適配器模式就可讓這些功能獲得更好的複用。 更好的擴展性 在實現適配器功能的時候,能夠調用本身開發的功能,從而天然地擴展系統的功能。 適配器模式的缺點 過多的使用適配器,會讓系統很是零亂,不易總體進行把握。好比,明明看到調用的是A接口,其實內部被適配成了B接口的實現,一個系統若是太多出現這種狀況,無異於一場災難。所以若是不是頗有必要,能夠不使用適配器,而是直接對系統進行重構。
Mbatis 日誌收集分析
Java開發中常常用到的日誌框架有不少,Log4j、Log4j二、slf4j等等,Mybatis定義了一套統一的日誌接口供上層使用,併爲上述經常使用的日誌框架提供了相應的適配器 在Mybatis的日誌模塊中就是使用了適配器模式。Mybatis內部在使用日誌模塊時,使用了其內部接口 org.apache.ibatis.logging.Log,可是經常使用的日誌框架的對外接口各不相同,Mybatis爲了複用和集成這些第三方日誌組件,在其日誌模塊中,提供了多種Adapter,將這些第三方日誌組件對外接口適配成org.apache.ibatis.logging.Log,這樣Myabtis 就能夠經過Log接口調用第三方日誌了
源碼分析圖
源碼剖析
Mybatis Log接口:至關於源接口
package org.apache.ibatis.logging; public interface Log { boolean isDebugEnabled(); boolean isTraceEnabled(); void error(String s, Throwable e); void error(String s); void debug(String s); void trace(String s); void warn(String s); }
Mybatis源接口實現類
適配器第一種
package org.apache.ibatis.logging.slf4j; import org.apache.ibatis.logging.Log; import org.slf4j.Logger; //Slf4jLoggerImpl :至關於適配器 //Log :至關於源接口 class Slf4jLoggerImpl implements Log { //Logger:至關於目標接口 private Logger log; public Slf4jLoggerImpl(Logger logger) { //源=目標 log = logger; }
適配器第二種
package org.apache.ibatis.logging.log4j2; import org.apache.ibatis.logging.Log; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.spi.AbstractLogger; //Log4j2Impl :至關於適配器 //Log :至關於源接口 public class Log4j2Impl implements Log { private Log log; //構造器 public Log4j2Impl(String clazz) { //目標接口 Logger logger = LogManager.getLogger(clazz); //判斷類型去實現:至關於目標 if (logger instanceof AbstractLogger) { log = new Log4j2AbstractLoggerImpl((AbstractLogger) logger); } else { //源=目標 log = new Log4j2LoggerImpl(logger); } }
目標接口:Logger
版權@須臾之餘https://my.oschina.net/u/3995125
本文參考:螞蟻課堂:http://www.mayikt.com