设计模式-适配器模式
什么是适配器模式
将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(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 类中我们可以根据需要选择并创建任一种符合需求的子类,来实现具体功能。
实现
创建被适配的类
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{
@Override
public void request() {
//...一些操作...
super.adapteeRequest();
//...一些操作...
}
}
对象适配器
对象适配器与类适配器不同之处在于,类适配器通过继承来完成适配,对象适配器则是通过关联来完成,这里稍微修改一下
Adapter
类即可将转变为对象适配器
public class Adapter implements Target{
// 适配者是对象适配器的一个属性
private Adaptee adaptee = new Adaptee();
@Override
public void request() {
//...
adaptee.adapteeRequest();
//...
}
}
注意这里的 Adapter 是将 Adaptee 作为一个成员属性,而不是继承它
接口适配器
当不需要全部实现接口提供的方法时,可先设计一个抽象类实现接口,并为该接口中每个方法提供一个默认实现(空方法),那么该抽象类的子类可有选择地覆盖父类的某些方法来实现需求,它适用于一个接口不想使用其所有的方法的情况。
手机品牌接口
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 "三星";
}
}