适配器模式(Adapter Pattern)的核心概念是将一个类的接口转换成客户期望的另一个接口,从而让原本接口不兼容的类能够合作无间。适配器模式通过引入一个适配器类来实现这种转换,适配器类通常持有源类(即被适配的类)的引用,并实现目标接口(即客户期望的接口)。客户端代码通过调用适配器类的方法来间接调用源类的方法,从而实现接口的适配。
适配器模式的角色概念:
适配器模式主要分三种:类适配器模式、对象适配器模式、接口适配器模式(默认适配器模式)。
下面将给出代码,并简要说明它们的使用场景以及各自的优缺点。
// 源类(Adaptee)
public class Adaptee {
public void specificRequest() {
System.out.println("源类特有请求");
}
}
// 目标接口(Target)
public interface Target {
void request();
}
// 类适配器(继承源类,实现目标接口)
public class ClassAdapter extends Adaptee implements Target {
@Override
public void request() {
specificRequest(); // 调用源类的方法
System.out.println("类适配器对请求进行了适配");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Target target = new ClassAdapter();
target.request();
}
}
当你想将一个已经存在的类适配到一个不兼容的接口,并且这个类的方法在适配器中都会被用到时,可以使用类适配器模式。
// 源类(Adaptee,与类适配器模式中的相同)
// 目标接口(Target,与类适配器模式中的相同)
// 对象适配器(持有源类的引用,实现目标接口)
public class ObjectAdapter implements Target {
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.specificRequest(); // 调用源类的方法
System.out.println("对象适配器对请求进行了适配");
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target target = new ObjectAdapter(adaptee);
target.request();
}
}
当你想将一个已经存在的类适配到一个不兼容的接口,但你不想使用继承或者源类的方法在适配器中不会被全部用到时,可以使用对象适配器模式。
// 目标接口(有很多方法)
public interface Target {
void method1();
void method2();
// ... 其他方法
}
// 抽象适配器类(实现目标接口,提供所有方法的默认实现)
public abstract class AbstractAdapter implements Target {
@Override
public void method1() { /* 默认实现 */ }
@Override
public void method2() { /* 默认实现 */ }
// ... 其他方法的默认实现
}
// 具体适配器类(继承抽象适配器类,重写需要的方法)
public class ConcreteAdapter extends AbstractAdapter {
@Override
public void method1() {
// 实现具体功能
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Target adapter = new ConcreteAdapter();
adapter.method1(); // 调用具体功能
// adapter.method2(); 使用默认实现,如果需要的话
}
}
当一个接口有很多方法,但客户端只对其中的一部分方法感兴趣,或者想要提供一个只需要实现部分方法的默认实现时,可以使用接口适配器模式。
与装饰器模式(Decorator Pattern)相比,适配器模式和装饰器模式都涉及到对类和接口的包装和扩展,但它们的侧重点和目的不同。
1. 侧重点不同:适配器模式主要解决的是接口不兼容的问题,它并不关注对象的功能增强,而是专注于将已有的功能通过适配器类以新的接口形式暴露给客户端。而装饰器模式则侧重于对对象的功能进行扩展和增强,它通常在不改变原有对象的基础上,动态地给对象添加一些额外的职责或行为。
2. 目的不同:适配器模式的主要目的是解决接口不兼容的问题,使得原本无法协同工作的类能够一起工作。而装饰器模式的主要目的是在不改变原有类的基础上,动态地扩展类的功能,增加类的职责。
3. 包装形式不同:适配器模式通常是通过继承或关联关系来实现接口的适配,它可能会改变原有接口的结构和形式。而装饰器模式则是通过组合关系来扩展对象的功能,它通常保持原有接口的稳定性和一致性。
4. 使用场景不同:适配器模式通常用于系统升级、代码重构等场景,当原有系统的接口无法满足新系统的需求时,可以使用适配器模式进行接口的适配。而装饰器模式则常用于需要在运行时动态地给对象添加功能或职责的场景,如Java IO流中的BufferedInputStream、BufferedReader等就是典型的装饰器模式的应用。
综上所述,适配器模式和装饰器模式虽然都涉及到对类和接口的包装和扩展,但它们的侧重点、目的、包装形式和使用场景都有所不同。在实际应用中,应根据具体的需求和场景来选择合适的设计模式。
术因分享而日新,每获新知,喜溢心扉。 诚邀关注公众号 『
码到三十五
』 ,获取更多技术资料。