这是我参与2022首次更文挑战的第15天,活动详情查看:2022首次更文挑战
适配器模式
适配器模式概念
适配器模式(Adapter Pattern),也叫包装模式(Wrapper),主要功能是将一个类的接口变成客户端所希望的另外一个接口,适配器模式可以作为两个不兼容的接口之间的桥梁,从而使因接口不匹配而导致无法在一起工作的类能够一起工作,在类的过程中,适配器模式属于结构性模式。
从另外一个角度上来讲,如果存在一个系统,系统中存在两个接口A和B,客户只能访问A接口,但是如果系统中没有A对象,有B对象,但是客户无法访问B接口,所以需要一个适配器C类,将B类接口的内容转换为A接口,因此客户可以访问A接口从而得到B接口的内容。
在软件工程中,任何情况都可以通过增加一个中间层来进行解决。而适配器就是这个中间层。
适配器模式应用场景
-
Tomcat中如何将Request流转换成为标准的Request
-
如何让tomcat使用CoyoteAdapte从而使用ServletRequest
-
Spring AOP中的AdvisorAdapter的前置适配器、后置适配器等方法
-
Spring MVC中经典的HandlerAdapter犯法的使用
适配器模式的通用写法
通常情况下适配器一般包含三种角色
-
目标角色(Target):目标抽象类,
-
源角色(Adaptee):存在于系统中,通过转换可以变成客户的需要的功能,但是接口不匹配的实例
-
适配器角色(Adapter):将源角色转换为目标角色的中间类。
适配器模式各个角色的关系基本如下:客户端需要访问Target接口,但是Target接口没有一个实例符合客户需求,而Adaptee类符合客户需求,但是客户端不能直接访问Adaptee类,因此我们需要一个Adapter类将Adaptee类转换封装称为Target接口,从而提供给客户端使用。
具体代码实现如下
- 源角色(Adaptee)
public class Adaptee {
public int specificRequest() {
return 225;
}
}
- 目标角色(Target)
public interface Target {
int request();
}
- 适配器角色(Adapter)
public class Adapter extends Adaptee implements Target {
@Override
public int request() {
return super.specificRequest() / 10;
}
}
- UML结构图
通过上述代码可以知道Adapter就可以知道他具备了Target和Adaptee两个角色功能,就可以将两者相互的转化。
适配器模式的优缺点
优点
- 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
- 增加了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来说是透明的,而且提高了适配者的复用性。
- 灵活性和扩展性都非常好,通过使用配置文件,可以很方便地更换适配器,也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。
缺点
- 过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
- 由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。增加代码的阅读难度,降低代码的可读性。
适配器模式和装饰器模式的区别
-
相同点
- 装饰器模式和适配器模式都是包装模式。
-
不同点
-
适配器模式没有层级关系,而装饰器模式存在层级关系
-
装饰器模式是被装饰类和装饰类都实现同一个接口,适配器模式中适配类和被适配类没有必然的关系,
-
适配器满足has-a的关系,而装饰器满是is-a的关系
-
适配器注重于兼容和转换的功能,装饰器模式注重于扩展和覆盖的功能
-