一.概念
将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
在适配器模式中,我们通过增加一个新的适配器类来解决接口不兼容的问题,使得原本没有任何关系的类可以协同工作。
根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器和类适配器两种,在对象适配器模式中,适配器与适配者之间是关联关系;在类适配器模式中,适配器与适配者之间是继承(或实现)关系。
缺省适配器模式(Default Adapter Pattern):当不需要实现一个接口所提供的所有方法时,可先设计一个抽象类实现该接口,并为接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可以选择性地覆盖父类的某些方法来实现需求,它适用于不想使用一个接口中的所有方法的情况,又称为单接口适配器模式。缺省适配器模式是适配器模式的一种变体,其应用也较为广泛。在JDK类库的事件处理包java.awt.event中广泛使用了缺省适配器模式,如WindowAdapter、KeyAdapter、MouseAdapter等。
适配器模式实现的方式有三种:类适配器,对象适配器,接口适配器。
二.角色
-
Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。
-
Adapter(适配器类):适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系。
-
Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下可能没有适配者类的源代码。
三.优缺点
优点
- 可以让任何两个没有关联的类一起运行。
- 提高了类的复用。
- 增加了类的透明度。
- 灵活性好。
缺点
- 过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
- 由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。
四.适用场景
-
想要使用一个已经存在的类,但是它却不符合现有的接口规范,导致无法直接去访问,这时创建一个适配器就能间接去访问这个类中的方法。
-
我们有一个类,想将其设计为可重用的类(可已经被多处访问了),我们可以创建适配器来将这个类来适配其他没有提供合适接口的类。
-
想要使用接口中的某个或者某些方法,但是接口中有太多不是自己需要的方法了,接口在实现时必须实现其中的所有方法,这个时候就要使用抽象类来实现接口,并不对所有方法进行实现(进置空),然后我们再继承这个抽象类来重写想要的方法。这个抽象类就是适配器
五.类适配器
Adapter 类继承Adaptee (被适配类),同时实现Target 接口(因为 Java 不支持多继承,所以只能通过接口的方法来实现多继承),在 Client 类中我们可以根据需要选择并创建任一种符合需求的子类,来实现具体功能。
1.实现
创建被适配的类
public class Adaptee {public void adapteeRequest() {System.out.println("被适配者的方法");}
}
定义一个目标接口
public interface Target {void request();
}
创建适配器类
实现 Target 接口,同时继承了 Adaptee 类,然后在实现的 **request()**方法中调用父类的 adapteeRequest()
public class Adapter extends Adaptee implements Target{@Overridepublic void request() {//...一些操作...super.adapteeRequest();//...一些操作...}
}
六.对象适配器
对象适配器与类适配器不同之处在于,类适配器通过继承来完成适配,对象适配器则是通过关联来完成,这里稍微修改一下 Adapter
类即可将转变为对象适配器
1.实现
public class Adapter implements Target{// 适配者是对象适配器的一个属性private Adaptee adaptee = new Adaptee();@Overridepublic void request() {//...adaptee.adapteeRequest();//...}
}
注意这里的 Adapter 是将 Adaptee 作为一个成员属性,而不是继承它
七.接口适配器
当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求,它适用于一个接口不想使用其所有的方法的情况。
1.实现
手机品牌接口
public interface MobilePhoneBrand {String xiaomi();String huawei();String apple();String vivo();String oppo();String samsung();
}
创建抽象类
public abstract class MobilePhoneDefault implements MobilePhoneBrand{public String xiaomi(){return null;}public String huawei(){return null;}public String apple(){return null;}public String vivo(){return null;}public String oppo(){return null;}public String samsung(){return null;}}
创建具体实现类
中国手机品牌
public class ChinaMobilePhone extends MobilePhoneDefault {public String xiaomi(){return "小米";}public String huawei(){return "华为";}public String vivo(){return "VIVO";}public String oppo(){return "OPPO";}}
美国手机品牌
public class USAMobilePhone extends MobilePhoneDefault {public String apple(){return "苹果";}
}
韩国手机品牌
public class KoreaMobilePhone extends MobilePhoneDefault {public String samsung(){return "三星";}
}