适配器(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