將一個類的接口轉換為客戶希望的另一個接口,使得原本由於接口不兼容而不能一起工作的那些類可以一起工作。
適配器是Adapter,也叫做Wrapper,是指如果一個接口需要B接口,但是待傳入的對象確是A接口,怎么辦?
我們舉個例子,如果去了美國,我們隨身攜帶的電器是無法直接使用的,因為美國的插座標注安和中國不同,所以,我們需要一個適配器。
在程序設計的過程中,適配器也是類似的,我們已經有了一個Task類,實現Callable接口:
public class Task implements Callable<Long> { private long num; public Task(long num) { this.num = num; } public Long call() throws Exception { long r = 0; for (long n = 1; n <= this.num; n++) { r = r + n; } System.out.println("Result: " + r); return r; } }
現在,我們想通過一個線程去執行它:
Callable<Long> callable = new Task(123450000L); Thread thread = new Thread(callable); // compile error! thread.start();
發現編譯不過!因為Thread接收Runnable接口,但是不接受Callable接口,怎么辦?
一個辦法是改寫Task類,把實現的Callable改為Runnable,這樣做不好,因為Task很可能在其他地方作為Callable唄應用,改寫Task的接口,會導致其他正常工作的代碼無法編譯。
另一個辦法不用改寫Task類,而是使用一個Adapter,把這個Callabble接口變成Runnable接口,這樣就可以正常編譯了:
Callable<Long> callable = new Task(123450000L); Thread thread = new Thread(new RunnableAdapter(callable)); thread.start();
這個RunnableAdapter類就是Adapter,他接受一個Callable,輸出一個Runnable。怎么實現這個RunnableAdapter呢?我們先看完整的代碼:
‘
public class RunnableAdapter implements Runnable { // 引用待轉換接口: private Callable<?> callable; public RunnableAdapter(Callable<?> callable) { this.callable = callable; } // 實現指定接口: public void run() { // 將指定接口調用委托給轉換接口調用: try { callable.call(); } catch (Exception e) { throw new RuntimeException(e); } } }
編寫一個Adapter的步驟如下:
1.實現目標接口,這里是Runnale;
2.內部持有一個待轉換接口的引用,這里是通過字段持有Callable接口;
3.在目標接口的實現方法內部,調用待轉換接口的方法。
這樣依賴,Thread接口已接收這個RunnableAdapter,因為它內部實現了Runnabble接口。Thread作為調用方,他會調用RunnabbleAdapter的run()方法,在這個方法內,又調用了Callable的call()方法,相當於Thread通過一層轉換,間接調用了Callable的call()方法。
適配器模式在Java表轉庫中有光放應用比如我們持有數據類型是String[],但是需要list接口,可以使用一個Adapter:
String[] exist = new String[] {"Good", "morning", "Bob", "and", "Alice"}; Set<String> set = new HashSet<>(Arrays.asList(exist));
注意到List<T>Arrays.asList(T[])就相當於一個轉換器,可以把數組轉換為List。
我們再看一個例子:假設我們持有一個InputStream,希望調用readText(Reader)方法,但是它的參數類型是Reader而不是InputStream,怎么辦?
當然是使用適配器,把InputStream變成Reader:
InputStream input = Files.newInputStream(Paths.get("/path/to/file")); Reader reader = new InputStreamReader(input, "UTF-8"); readText(reader);
InputStreamReader就是Java再看提供的ADapter,他蹙着把一個InputStream適配為Reader。類似的還有OutputStreamWriter。