一、适配器模式概述
适配器模式(Adapter Pattern)是一种结构型设计模式,它的作用是将一个类的接口转换成客户期望的另一个接口,从而解决接口不兼容导致无法协同工作的问题。适配器模式常用于需要将不同接口的类进行组合、集成时,尤其是在老旧系统与新系统之间的接口适配中非常常见。
举个例子,假如你要去美国旅游,你的电器设备无法直接插入美国的插座,因为插座类型不同,此时你需要一个适配器将中国的插头转换为美国插座。程序设计中的适配器模式正是用来解决接口不兼容的问题。
二、适配器模式的工作原理
2.1 适配器模式示例
假设我们有一个实现了Callable
接口的Task
类:
java
public class Task implements Callable<Long> {
private long num;
public Task(long num) {
this.num = num;
}
public Long call() throws Exception {
long result = 0;
for (long n = 1; n <= this.num; n++) {
result += n;
}
System.out.println("Result: " + result);
return result;
}
}
现在,我们希望通过线程来执行这个任务。可是,Thread
类接收的是Runnable
接口,而不是Callable
接口,因此会报错:
java
Callable<Long> callable = new Task(123450000L);
Thread thread = new Thread(callable); // 编译错误
thread.start();
这个问题的解决方法是使用适配器模式。我们不直接修改Task
类,而是创建一个适配器,将Callable
接口适配为Runnable
接口。
2.2 创建适配器
下面是适配器的实现:我们编写一个RunnableAdapter
类,实现了Runnable
接口,并内部持有一个Callable
接口的实例:
java
public class RunnableAdapter implements Runnable {
private Callable<?> callable;
public RunnableAdapter(Callable<?> callable) {
this.callable = callable;
}
@Override
public void run() {
try {
callable.call();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
这里,RunnableAdapter
类实现了Runnable
接口,并通过call()
方法将Callable
接口的调用转发给内部的callable
实例。这样,我们就可以通过适配器将Task
类适配为Runnable
,从而能够正常编译:
java
Callable<Long> callable = new Task(123450000L);
Thread thread = new Thread(new RunnableAdapter(callable));
thread.start();
三、适配器模式的实现步骤
编写适配器模式时,可以遵循以下步骤:
-
实现目标接口:首先,定义我们需要适配的目标接口,在本例中是
Runnable
接口。 -
持有待转换接口的引用:适配器类内部通过字段持有一个待适配的接口实例,通常是
Callable
。 -
在目标接口方法中调用待适配接口的方法:适配器类的目标方法(如
run()
)内部调用待适配接口的原有方法(如call()
)。
通过这样的方式,我们就能使得不兼容的接口能够协同工作。
四、适配器模式在Java中的应用
4.1 数组转集合的适配
在Java标准库中,Arrays.asList()
方法将数组转换为List
接口,就实现了数组与集合类型之间的适配:
java
String[] exist = new String[] {"Good", "morning", "Bob", "and", "Alice"};
Set<String> set = new HashSet<>(Arrays.asList(exist));
在这里,Arrays.asList()
充当了适配器,将String[]
类型转换成了List<String>
类型。
4.2 输入输出流的适配
在I/O操作中,适配器模式也有广泛应用。比如,我们有一个InputStream
对象,而需要将其传入一个readText(Reader)
方法中:
java
InputStream input = Files.newInputStream(Paths.get("/path/to/file"));
Reader reader = new InputStreamReader(input, "UTF-8");
readText(reader);
在这段代码中,InputStreamReader
就是一个适配器,它将InputStream
转换成了Reader
。类似地,OutputStreamWriter
将OutputStream
适配为Writer
。
4.3 适配器解决类间不兼容问题
有时候我们需要将一个接口适配为具体的类。例如,如果我们需要FileReader
,但手头只有InputStream
,我们就需要适配器:
java
FileReader reader = new InputStreamReader(input, "UTF-8"); // 编译错误
InputStreamReader
可以将InputStream
适配为Reader
,但如果需要FileReader
,就需要更多的适配工作,可能需要创建一个新的适配器。此时,抽象编程原则的优势显现出来,持有抽象接口使得接口组合和适配变得更加灵活。
五、练习:使用适配器模式将Callable适配为Runnable
-
实现一个适配器,将
Callable
接口适配为Runnable
接口。 -
编写一个测试类,使用
RunnableAdapter
来启动一个线程执行Task
类。
示例代码:
java
public class Main {
public static void main(String[] args) {
Callable<Long> callable = new Task(1000L);
Thread thread = new Thread(new RunnableAdapter(callable));
thread.start();
}
}
六、小结
适配器模式(Adapter Pattern)是一种结构型设计模式,主要用于将一个类的接口转换成客户期望的另一个接口,从而解决类之间接口不兼容的问题。通过适配器模式,我们可以轻松地实现不同接口之间的转换,从而让不兼容的类能够一起工作。
适配器模式的实现通常包括:
-
实现目标接口。
-
持有待适配接口的实例。
-
将目标接口方法的调用委托给待适配接口。
适配器模式在Java标准库中有广泛应用,如Arrays.asList()
方法、InputStreamReader
等。
适配器模式非常适合于不同接口或类之间的衔接,可以提高代码的灵活性与可扩展性。