适配器模式是一种结构型设计模式,它允许不同接口的对象协同工作,它通过将一个类的接口转换成客户希望的另外一个接口,使得不兼容的类可以一起工作。适配器模式提高了类的复用性、系统的灵活性和可扩展性,并降低了系统间的耦合度,在实际应用中,例如电源适配器和数据转换器,以及编程中封装老旧接口或第三方库都体现了适配器模式的应用。
适配器模式(Adapter Pattern)是一种结构型设计模式,它允许对象具有不同的接口协同工作,这种类型的设计模式属于结构模式,因为此模式作用于对象的结构。
在适配器模式中,我们通过将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。它的主要作用是解决两个已有接口间不兼容的问题,它允许我们在不修改现有代码的情况下,将两个不兼容的接口通过适配器进行对接,从而使得它们能够协同工作,它在实际应用中的例子有很多,比如电源适配器、数据转换器等。在编程中,适配器模式也经常用于封装老旧的接口或者第三方库,以便它们能够与新的代码或框架协同工作,适配器模式的主要优点有:
下面演示了未使用适配器模式的代码和使用了适配器模式的代码,如下代码:
1、未使用适配器模式的反例,假设我们有一个已有的类 OldClass,这个类的方法不满足客户端的需求:
// 已有的类,不满足客户端需求
public class OldClass {
public void specificRequest() {
System.out.println("OldClass specific request.");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
OldClass oldClass = new OldClass();
// 客户端需要调用 request() 方法,但是 OldClass 没有此方法
// oldClass.request(); // 这行代码会导致编译错误
oldClass.specificRequest(); // 只能调用已有的方法
}
}
在上述反例中,Client
希望调用一个名为 request()
的方法,但是 OldClass
只有 specificRequest()
方法,这导致 Client
无法直接使用 OldClass
。
2、使用适配器模式的正例,为了解决上述问题,我们可以使用适配器模式,将一个类的接口转换成客户端所期望的另一种接口,从而使得原本由于接口不兼容而无法在一起工作的类能够一起工作,如下代码:
// 目标接口,定义客户端需要的方法
public interface Target {
void request();
}
// 适配器类,继承 OldClass 并实现 Target 接口
public class Adapter extends OldClass implements Target {
@Override
public void request() {
// 调用 OldClass 的 specificRequest() 方法,并可能进行其他操作以满足客户端需求
super.specificRequest();
System.out.println("Adapter additional operation.");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
// 使用适配器类,而不是直接使用 OldClass
Target target = new Adapter();
target.request(); // 现在可以调用 request() 方法了
}
}
运行上述客户端代码后,输出将会是:
OldClass specific request.
Adapter additional operation.
通过适配器模式,我们成功地让 Client
能够使用 OldClass
的功能,同时满足了自己对接口的需求。在适配器中,我们可以添加额外的操作或转换来满足客户端的需求。
场景一:电源适配器
假设我们有一个Voltage220类提供220V电压,但我们需要一个110V的电压接口,此时,我们可以使用适配器模式将220V电压适配为110V电压,如下代码:
// 目标接口
public interface Voltage110 {
int output110Voltage();
}
// 已有的类,提供220V电压
public class Voltage220 {
public int output220Voltage() {
return 220;
}
}
// 电源适配器类
public class PowerAdapter implements Voltage110 {
private Voltage220 voltage220;
public PowerAdapter(Voltage220 voltage220) {
this.voltage220 = voltage220;
}
@Override
public int output110Voltage() {
int srcVoltage = voltage220.output220Voltage();
int dstVoltage = srcVoltage / 2; // 适配为110V电压
return dstVoltage;
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
Voltage220 voltage220 = new Voltage220();
PowerAdapter powerAdapter = new PowerAdapter(voltage220);
int adaptedVoltage = powerAdapter.output110Voltage();
System.out.println("Adapted voltage: " + adaptedVoltage + "V"); // 输出:Adapted voltage: 110V
}
}
场景二:数据格式转换
假设我们有一个老的数据读取接口OldDataReader,它返回的数据格式是XML,但现在我们需要一个返回JSON格式数据的新接口,我们可以使用适配器模式来完成这个转换,如下代码:
// 目标接口,返回JSON格式数据
public interface NewDataReader {
String readDataAsJson();
}
// 已有的类,返回XML格式数据
public class OldDataReader {
public String readDataAsXml() {
return "- Item1
- Item2
"; // 示例XML数据
}
}
// 数据格式适配器类
import org.json.XML; // 假设我们使用org.json库进行XML到JSON的转换
public class DataFormatAdapter implements NewDataReader {
private OldDataReader oldDataReader;
public DataFormatAdapter(OldDataReader oldDataReader) {
this.oldDataReader = oldDataReader;
}
@Override
public String readDataAsJson() {
String xmlData = oldDataReader.readDataAsXml();
String jsonData = XML.toJSONObject(xmlData).toString(); // 将XML转换为JSON
return jsonData;
}
}
// 客户端调用
public class Client {
public static void main(String[] args) {
OldDataReader oldDataReader = new OldDataReader();
DataFormatAdapter dataFormatAdapter = new DataFormatAdapter(oldDataReader);
String jsonData = dataFormatAdapter.readDataAsJson();
System.out.println("Adapted JSON data: " + jsonData); // 输出转换后的JSON数据
}
}
适配器模式的优点主要表现在兼容性、透明性、灵活性和解耦四个方面。它能够将已存在的类整合到新的环境中,无需修改原有代码,从而提高了软件的可复用性,客户端通过适配器与目标对象交互,仍能使用一套统一的接口,对客户端透明,简化了客户端的使用。适配器模式将接口与实现分离,降低了系统各部分之间的耦合度,使得系统更加模块化,易于维护。
在实际应用中,适配器模式在处理老旧系统与新系统整合、第三方库的使用以及不同团队或部门间接口不统一等问题上效果显著,它使得原本由于接口不兼容而无法协同工作的类能够合作无间,提高了系统的整体效率和可维护性。比如,在引入新的第三方库时,如果其接口与现有系统不兼容,我们可以通过适配器模式将两者整合在一起,而无需对现有系统进行大规模修改。
适配器模式也存在一些缺点,比如:增加额外类和代码可能导致系统复杂性上升,由于中间层的存在,可能带来一定的性能开销,过多使用适配器会使代码结构变得复杂,影响可读性。
要适度使用适配器模式,只在必要时使用,避免过度复杂化系统,要明确适配器的目标接口,确保其与客户端需求一致。在性能敏感的场景下,需谨慎评估适配器模式带来的性能开销,可以考虑结合其他设计模式如桥接模式、装饰器模式等使用,以应对更复杂的场景。比如,在需要动态添加或删除功能时,可以结合装饰器模式使用;在需要处理多个平台或设备的兼容性问题时,可以结合桥接模式使用。