在 Java 中,适配器模式是一种设计模式,它允许将一个类的接口转换成另一个接口,以便于两个接口不兼容的类可以一起工作。
适配器模式有四个角色:
- Target:定义客户端所需的接口。
- Adapter:适配器类,实现了 Target 接口,并且包含一个 Adaptee 类型的对象。
- Adaptee:定义了一个已有的接口,这个接口需要适配。
- Client:使用 Target 接口的对象。
适配器模式常常被用在两个接口之间的转换上,这样就可以使得原本由于接口不兼容而不能一起工作的类可以一起工作。
下面是一个简单的示例,演示了如何使用适配器模式在 Java 中将一个类的接口转换成另一个接口:
// Target interface
public interface Voltage5V {
int output5V();
}
// Adaptee class
public class Voltage220V {
public int output220V() {
int src = 220;
System.out.println("电压=" + src + "伏");
return src;
}
}
// Adapter class
public class VoltageAdapter implements Voltage5V {
private Voltage220V mVoltage220V;
public VoltageAdapter(Voltage220V voltage220V) {
mVoltage220V = voltage220V;
}
@Override
public int output5V() {
int src = mVoltage220V.output220V();
int dst = src / 44;
System.out.println("适配器工作,开始适配电压");
System.out.println("原始电压=" + src + "V");
System.out.println("适配后电压=" + dst + "V");
return dst;
}
}
// Client
public class Phone {
public void charging(Voltage5V voltage5V) {
if (voltage5V.output5V() == 5) {
System.out.println("电压刚好5V,开始充电");
} else if (voltage5V.output5V() > 5) {
System.out.println("电压超过5V,部分能量浪费");
} else {
System.out.println("电压不足5V,无法充电");
}
}
}
// Test
public class Test {
public static void main(String[] args) {
Phone phone = new Phone();
Voltage220V voltage220V = new Voltage220V();
VoltageAdapter voltageAdapter = new VoltageAdapter(voltage220V);
phone.charging(voltageAdapter);
}
}
在这个示例中,Voltage220V 类是 Adaptee,Voltage5V 接口是 Target,VoltageAdapter 类是 Adapter,Phone 类是 Client。VoltageAdapter 类实现了 Voltage5V 接口,并且包含一个 Voltage220V 类型的对象,它可以将 Voltage220V 类的 output220V() 方法转换成 Voltage5V 接口的 output5V() 方法,这样就可以使 Phone 类可以使用 Voltage220V 类的接口进行充电。
这是另一个使用适配器模式的示例,演示了如何使用适配器将枚举转换成迭代器:
import java.util.Enumeration;
import java.util.Iterator;
// Target interface
public interface IteratorAdapter {
Iterator getIterator();
}
// Adaptee class
public class EnumerationAdapter implements IteratorAdapter {
private Enumeration enumeration;
public EnumerationAdapter(Enumeration enumeration) {
this.enumeration = enumeration;
}
@Override
public Iterator getIterator() {
return new Iterator() {
@Override
public boolean hasNext() {
return enumeration.hasMoreElements();
}
@Override
public Object next() {
return enumeration.nextElement();
}
};
}
}
// Client
public class Test {
public static void main(String[] args) {
String[] array = {"a", "b", "c"};
Enumeration enumeration = new ArrayEnumeration(array);
EnumerationAdapter adapter = new EnumerationAdapter(enumeration);
Iterator iterator = adapter.getIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
在这个示例中,Enumeration 类是 Adaptee,IteratorAdapter 接口是 Target,EnumerationAdapter 类是 Adapter,Test 类是 Client。EnumerationAdapter 类实现了 IteratorAdapter 接口,并且包含一个 Enumeration 类型的对象,它可以将 Enumeration 类的 hasMoreElements() 和 nextElement() 方法转换成 Iterator 接口的 hasNext() 和 next() 方法,这样就可以使 Test 类可以使用 Enumeration 类的接口进行迭代。
下面是一个在实际开发中使用适配器模式的例子,演示了如何使用适配器将不同的日志库适配到统一的日志接口:
import java.util.logging.Logger;
// Target interface
public interface Log {
void info(String message);
void error(String message);
}
// Adaptee class
public class JdkLog implements Log {
private Logger logger;
public JdkLog(Logger logger) {
this.logger = logger;
}
@Override
public void info(String message) {
logger.info(message);
}
@Override
public void error(String message) {
logger.severe(message);
}
}
// Adapter class
public class Log4jLog implements Log {
private org.apache.log4j.Logger logger;
public Log4jLog(org.apache.log4j.Logger logger) {
this.logger = logger;
}
@Override
public void info(String message) {
logger.info(message);
}
@Override
public void error(String message) {
logger.error(message);
}
}
// Client
public class Test {
public static void main(String[] args) {
Log jdkLog = new JdkLog(Logger.getLogger("JDK Log"));
jdkLog.info("JDK log info message");
jdkLog.error("JDK log error message");
Log log4jLog = new Log4jLog(org.apache.log4j.Logger.getLogger("Log4j Log"));
log4jLog.info("Log4j log info message");
log4jLog.error("Log4j log error message");
}
}
在这个示例中,JdkLog 类是 Adaptee,Log 接口是 Target,Log4jLog 类是 Adapter,Test 类是 Client。JdkLog 和 Log4jLog 类都实现了 Log 接口,并且包含了对应的日志库的对象,它们可以将不同的日志库的方法转换成统一的日志接口的方法,这样就可以使 Test 类可以统一地使用不同的日志库记录日志。
没有接口如何使用适配器模式
如果没有 Target 接口,也就是说 Adaptee 类和 Client 类之间没有公共接口可以使用,你可以使用适配器模式的另一种形式,即对象适配器。
对象适配器与类适配器的区别在于,类适配器使用继承的方式将 Adaptee 类的接口转换成 Target 接口,而对象适配器使用组合的方式将 Adaptee 类的对象包装在 Adapter 类中,并且 Adapter 类实现了 Target 接口。
下面是一个使用对象适配器模式的示例,演示了如何将一个类的接口转换成另一个接口:
// Adaptee class
public class Adaptee {
public void adapteeMethod() {
System.out.println("Adaptee method");
}
}
// Target interface
public interface Target {
void targetMethod();
}
// Adapter class
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void targetMethod() {
adaptee.adapteeMethod();
}
}
// Client
public class Test {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target target = new Adapter(adaptee);
target.targetMethod();
}
}
在这个示例中,Adaptee 类是 Adaptee,Target 接口是 Target,Adapter 类是 Adapter,Test 类是 Client。Adapter 类实现了 Target 接口,并且包含了一个 Adaptee 类型的对象,它可以将 Adaptee 类的 adapteeMethod() 方法转换成 Target 接口的 targetMethod() 方法,这样就可以使 Test 类可以使用 Adaptee 类的接口。
总的来说,适配器模式是一种设计模式,它可以让两个接口不兼容的类可以一起工作。适配器模式有两种形式,分别是类适配器和对象适配器。类适配器使用继承的方式将 Adaptee 类的接口转换成 Target 接口,而对象适配器使用组合的方式将 Adaptee 类的对象包装在 Adapter 类中,并且 Adapter 类实现了 Target 接口。适配器模式可以解决接口不兼容的问题,并且可以使用时无需改变原有的代码,因此在软件开发中很常用。