适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。这种模式涉及到一个单一的类,该类负责加入独立的或不兼容的接口功能,让原来不兼容的两个接口协同工作。
定义
让原来不兼容的两个接口协同工作。
分类
角色
- 目标接口:Target,该角色把其他类转换为我们期望的接口
- 被适配者:Adaptee 原有的接口,也是希望被改变的接口
- 适配器: Adapter, 将被适配者和目标接口组合到一起的类
对象适配器
使用组合的方式,Target接口是我们需要操作的接口,我们的目标也是想让原有的接口(Adaptee )变成我们想要的接口(Target),适配器类(Adapter)需要实现Target接口,Adapter类里面组合了原有的接口(Adaptee ),相当于我们在使用Target的时候,间接的通过适配器操作了原来的接口,而又没改动原来的接口,也可以根据实际业务包装原来的接口来适应我们的业务,这样就只改动我们自己写的适配器类,没有改动到原来的接口,也符合开闭原则。
类图
![image-20220209171001573](https://guyou-blog.oss-cn-shenzhen.aliyuncs.com/static/image-20220209171001573.png)
代码实现
1 2 3 4 5 6
| public class ObjectAdaptee { public void specificRequest(){ System.out.println("原有的接口"); } }
|
1 2 3 4
| public interface Target { void request(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public class ObjectAdapter implements Target{
private ObjectAdaptee adaptee;
public ObjectAdapter(ObjectAdaptee adaptee){ this.adaptee = adaptee; }
@Override public void request() { adaptee.specificRequest(); } }
|
测试截图
![image-20220209170847538](https://guyou-blog.oss-cn-shenzhen.aliyuncs.com/static/image-20220209170847538.png)
类适配器
采用继承和实现的方式实现,需要适配器类(Adapter)继承原来的接口(Adaptee )并且实现目标接口(Target),因为是继承,所以我们的适配器类其实就是原来的接口类型,能操作原来接口的属性和方法,再通过实际业务更改适配器类里面的业务,这样也是符合开闭原则的,因为又实现了目标接口(Target),所有就把原来的接口(Target)变成了我们想要的接口类型(Target)。
类图
![image-20220209172805710](https://guyou-blog.oss-cn-shenzhen.aliyuncs.com/static/image-20220209172805710.png)
代码实现
1 2 3 4 5 6
| public class ObjectAdaptee {
public void specificRequest(){ System.out.println("原有的接口2..."); } }
|
1 2 3 4
| public interface Target { void request(); }
|
1 2 3 4 5 6 7
| public class ObjectAdapter extends ObjectAdaptee implements Target {
@Override public void request() { this.specificRequest(); } }
|
测试截图
![image-20220209173505686](https://guyou-blog.oss-cn-shenzhen.aliyuncs.com/static/image-20220209173505686.png)
接口适配器
当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求,适用于一个接口不想使用其所有的方法的情况。
类图
![image-20220210102530829](https://guyou-blog.oss-cn-shenzhen.aliyuncs.com/static/image-20220210102530829.png)
代码实现
1 2 3 4 5 6 7 8 9 10 11
| public interface ObjectAdaptee {
void eat();
void drink();
void paly();
void happy();
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public abstract class AbsAdapter implements ObjectAdaptee{
@Override public void eat() {
}
@Override public void drink() {
}
@Override public void paly() {
}
@Override public void happy() {
} }
|
测试截图
![image-20220210094222002](https://guyou-blog.oss-cn-shenzhen.aliyuncs.com/static/image-20220210094222002.png)
双向适配器
在对象适配器的使用过程中,如果在适配器中同时包含对目标类和适配者类的引用,适配者可以通过它调用目标类中的方法,目标类也可以通过它调用适配者类中的方法,那么该适配器就是一个双向适配器。
类图
![image-20220210100107397](https://guyou-blog.oss-cn-shenzhen.aliyuncs.com/static/image-20220210100107397.png)
代码实现
1 2 3
| public interface Target { void request(); }
|
1 2 3
| public interface Adaptee { void specificRequest(); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class Adapter implements Target,Adaptee{ private Target target; private Adaptee adaptee;
public Adapter(Target target){ this.target = target; }
public Adapter(Adaptee adaptee){ this.adaptee = adaptee; }
@Override public void specificRequest() { adaptee.specificRequest(); }
@Override public void request() { target.request(); } }
|
优点
- 可以让任何两个没有关联的类一起运行
- 提高了类的复用
- 增加了类的透明度
- 灵活性好
缺点
- 过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
- 由于 Java 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。