适配器模式(Adapter Pattern)是一种常见的设计模式,它属于结构型设计模式,用于将一个类的接口转换成客户端所期望的另一个接口,从而使两者能够协同工作。适配器模式主要用于解决接口不兼容的问题,它允许不同接口的类协同工作,而不需要修改它们的源代码。
适配器模式通常涉及以下几个部分:
适配器模式的主要目标是使客户端能够使用被适配对象,而无需修改客户端的代码。这通常在以下情况下使用:
下面是一个简单的示例,展示了适配器模式的使用:
// 目标接口
interface Target {
void request();
}
// 被适配对象
class Adaptee {
void specificRequest() {
System.out.println("Adaptee's specific request");
}
}
// 适配器
class Adapter implements Target {
private Adaptee adaptee;
Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
System.out.println("Adapter's request");
adaptee.specificRequest();
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target adapter = new Adapter(adaptee);
clientCode(adapter);
}
static void clientCode(Target target) {
target.request();
}
}
适配器模式有两种常见的变体:类适配器模式和对象适配器模式。它们都用于将一个类的接口转换成另一个接口,但它们实现的方式略有不同。
在很多情况下,对象适配器模式更常见,因为它更灵活,并且避免了一些多重继承可能引发的问题。类适配器模式在一些特定的情况下也可以派上用场,但需要小心使用,以避免潜在的继承冲突和复杂性,并且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少一些。
类适配器模式(Class Adapter Pattern)是一种适配器模式的变体,它用于将一个类的接口适配成另一个类的接口。在类适配器模式中,适配器类通过多重继承来实现目标接口和被适配对象的接口,同时继承了目标接口和被适配对象的类。
类适配器模式的关键要素:
下面用代码实现类适配器的示例
// 目标接口
interface Target {
void request();
}
// 被适配对象
class Adaptee {
public void specificRequest() {
System.out.println("Adaptee's specific request");
}
}
// 适配器类,通过多重继承同时实现Target接口和继承Adaptee类
class Adapter extends Adaptee implements Target {
public void request() {
System.out.println("Adapter's request");
specificRequest(); // 调用被适配对象的方法
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Target target = new Adapter();
target.request(); // 调用适配器的request方法,实际上委派给Adaptee的specificRequest方法
}
}
从上面的代码中可以得知,类适配器模式违背了合成复用原则。类适配器是客户类有一个接口规范的情况下可用,反之则不可用。并且如果适配器需要同时适配两个对象时,因为java是单继承的原因,而无法满足此需求。
对象适配器模式是一种设计模式,用于解决接口不兼容的问题。在对象适配器模式中,适配器类包含一个被适配对象的实例作为其属性,然后通过实现目标接口来将被适配对象的接口转换成客户端期望的接口。这种模式使用组合来实现适配,而不是使用多重继承。
以下是一个使用Java实现的对象适配器模式示例:
// 目标接口
interface Target {
void request();
}
// 被适配对象
class Adaptee {
public void specificRequest() {
System.out.println("Adaptee's specific request");
}
}
// 适配器类,通过组合被适配对象实例并实现目标接口来实现适配
class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
System.out.println("Adapter's request");
adaptee.specificRequest(); // 调用被适配对象的方法
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target target = new Adapter(adaptee);
target.request(); // 调用适配器的request方法,实际上委派给Adaptee的specificRequest方法
}
}
在上面示例中,Adapter
类包含一个Adaptee
对象的实例作为属性,然后实现了Target
接口。在Adapter
的request
方法中,它调用了Adaptee
的specificRequest
方法,实现了适配。
客户端代码首先创建一个Adaptee
对象,然后通过创建一个Adapter
对象并传递Adaptee
对象作为参数来实现适配。当客户端调用Adapter
的request
方法时,实际上调用了Adaptee
的方法,从而实现了适配。
运行客户端代码时,输出将会是:
Adapter's request
Adaptee's specific request
这表明对象适配器模式成功地将Adaptee
的接口适配成了Target
接口,使它们可以一起工作,而不需要修改Adaptee
的源代码。
注意:还有一个适配器模式是接口适配器模式。当不希望实现一个接口中所有的方法时,可以创建一个抽象类Adapter,实现所有方法。而此时只需要继承该抽象类即可。
以下是适配器模式的一些常见应用场景:
java.io.OutputStream
是一个抽象类,它定义了输出流的基本行为,而其子类可以根据需要实现特定的输出源。
以 FileOutputStream
为例,它是用于将数据写入文件的输出流。FileOutputStream
继承自 OutputStream
并实现了其中的抽象方法,同时提供了与文件相关的功能。下面是一个简单的示例,演示了如何使用 FileOutputStream
来写入数据到文件中:
import java.io.*;
public class FileOutputStreamExample {
public static void main(String[] args) {
String filename = "output.txt";
String data = "Hello, OutputStream example!";
try {
// 创建文件输出流
OutputStream outputStream = new FileOutputStream(filename);
// 将字符串数据转换为字节数组
byte[] bytes = data.getBytes();
// 使用输出流写入数据到文件
outputStream.write(bytes);
// 关闭输出流
outputStream.close();
System.out.println("Data has been written to " + filename);
} catch (IOException e) {
e.printStackTrace();
}
}
}
在这个示例中,使用了 FileOutputStream
来写入数据到文件 “output.txt” 中。FileOutputStream
是 OutputStream
的子类,它实现了 OutputStream
中的 write
方法,这个方法用于将数据写入输出流。
这里的关键是 FileOutputStream
充当了适配器的角色。它适配了 OutputStream
的接口,使得开发人员可以使用统一的输出流接口来写入数据到文件,而不必关心底层文件操作的细节。这种方式使代码更具可移植性和可维护性,因为可以轻松地切换不同的输出流类型(如网络流、内存流等),而不必改变写入数据的方式。
在 FileOutputStream
内部,它通过适配 OutputStream
接口,将写入文件的操作转化为文件系统的底层操作,这就是适配器模式的应用之一(对象适配器模式)。