適配器(Adapter、Wrapper)


將一個類的接口轉換為客戶希望的另一個接口,使得原本由於接口不兼容而不能一起工作的那些類可以一起工作。

適配器是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。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM