将一个类的接口装换成客户但愿的另一个接口。适配器模式使得原来因为接口不兼容而不能一块儿工做的那些类能够一块儿工做。android
适配器模式由三部分组成:bash
- Target(目标抽象类):目标抽象类定义客户所需接口,能够是一个抽象类或接口,也能够是具体类。
- Adapter(适配器类):适配器能够调用另外一个接口,做为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心。
- Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口须要适配,适配者类通常是一个具体类,包含了客户但愿使用的业务方法。
2.2.1 Android(Target抽象类)框架
public interface Android {
void isAndroid();
}
复制代码
2.2.2 Iphone(Adaptee类)iphone
public class Iphone {
public void isIphone() {
System.out.println("这是一个适配苹果充电线的接口");
}
}
复制代码
2.2.3 Adapter类ide
/**
* 将安卓手机的接口转化为苹果手机可用的充电接口
*/
public class Adapter extends Iphone implements Android {
@Override
public void isAndroid() {
isIphone();
}
}
复制代码
2.2.4 客户端调用学习
public class Client {
public static void main(String[] args) {
Android android = new Adapter();
android.isAndroid();
}
}
复制代码
2.3.1 优势this
- 因为适配器类是适配者的子类,所以能够在适配器类中置换一些适配者的方法,使得适配器的灵活性更强。
2.3.1 缺点spa
- 对于Java、C#等不支持多重类继承的语言,一次最多只能适配一个适配者类,不能同时适配多个适配者。
- 适配者类不能为最终类,如在Java中不能为final类,C#中不能为sealed类。
- 在Java、C#等语言中,类适配器模式中的目标抽象类只能为借口,不能为类,其使用有必定的局限性。
角色与类适配器模式同样3d
3.2.1 Android(Target抽象类)code
public interface Android {
void isAndroid();
}
复制代码
3.2.2 Iphone(Adaptee类)
public class Iphone {
public void isIphone() {
System.out.println("这是一个适配苹果充电线的接口");
}
}
复制代码
3.2.3 Adapter类
/**
* 将安卓手机的接口转化为苹果手机可用的充电接口
*/
public class Adapter implements Android {
private Iphone iphone;
public Adapter(Iphone iphone) {
this.iphone = iphone;
}
@Override
public void isAndroid() {
iphone.isIphone();
}
}
复制代码
3.2.4 客户端调用
public class Client {
public static void main(String[] args) {
Android android = new Adapter(new Iphone());
android.isAndroid();
}
}
复制代码
3.3.1 优势
- 一个对象适配器能够把多个不一样的适配者适配到同一个目标。
- 能够适配一个适配者的子类,因为适配器和适配者之间是关联关系,根据“里氏替换原则”,适配者的子类也可经过该适配器进行适配。
3.3.2 缺点
- 与类适配器模式相比,要在适配器中置换适配者类的某些方法比较麻烦。若是必定要置换掉适配者类的一个或多个方法,能够先作一个适配者类的子类,将适配者类的方法置换掉,而后再把适配者类的子类当作真正的适配者进行适配,实现过程较为复杂。
缺省适配器由两部分组成:
- Target(目标角色):目标接口。能够定义有不少方法,但这些方法不必定全都被用户类所须要。
- Default Adapter(缺省适配器):缺省适配模式的核心。它实现Target角色接口,为因此方法提供空的实现。
4.2.1 Target
public interface SubjectTarget {
void learnChinese();
void learnEnglish();
void learnMath();
void learnBiological();
}
复制代码
4.2.2 Default Adapter
public abstract class SubjectAdapter implements SubjectTarget {
@Override
public void learnChinese() {
}
@Override
public void learnEnglish() {
}
@Override
public void learnMath() {
}
@Override
public void learnBiological() {
}
}
复制代码
4.2.3 客户端调用
public class Client {
public static void main(String[] args) {
SubjectAdapter subjectAdapter = new SubjectAdapter() {
@Override
public void learnEnglish() {
System.out.println("学习英语使我快乐");
}
};
subjectAdapter.learnEnglish();
}
}
复制代码
- 系统须要复用现有类,而该类的接口不符合系统的需求,可使用适配器模式使得本来因为接口不兼容而不能一块儿工做的那些类能够一块儿工做。
- 想建立一个能够重复使用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在未来引进的类一块儿工做。
- 灵活使用时:选择对象适配器。类适配器使用对象继承的方式,是静态的定义方式;而对象适配器使用对象组合的方式,是动态组合的方式。
- 须要同时配置源类和其子类:选择对象适配器。对于类适配器,因为适配器直接继承了Adaptee,使得适配器不能和Adaptee的子类一块儿工做,由于继承是静态的关系,当适配器继承了Adaptee后,就不可能再去处理Adaptee的子类;对于对象适配器,一个适配器能够把多种不一样的源适配到同一个目标。换言之,同一个适配器能够把源类和它的子类都适配到目标接口。由于对象适配器采用的是对象组合的关系,只要对象类型正确,是否是子类都无所谓。
- 须要从新定义Adaptee的部分行为:选择类适配器。对于类适配器,适配器能够重定义Adaptee的部分行为,至关于子类覆盖父类的部分实现方法。对于对象适配器,要重定义Adaptee的行为比较困难,这种状况下,须要定义Adaptee的子类来实现重定义,而后让适配器组合子类。虽然重定义Adaptee的行为比较困难,可是想要增长一些新的行为则方便的很,并且新增长的行为可同时适用全部的源。
- 仅仅但愿使用方便时:选择类适配器。对于类适配器,仅仅引入了一个对象,并不须要额外的引用来间接获得Adaptee。对于对象适配器,须要额外的引用来间接获得Adaptee。
- 将目标类和适配者类解耦,经过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
- 增长了类的透明性和复用性,将具体的实现封装在适配者类中,对于客户端类来讲是透明的,并且提升了适配者的复用性。
- 灵活性和扩展性都很是好,经过使用配置文件,能够很方便地更换适配器,也能够在不修改原有代码的基础上增长新的适配器类,彻底符合“开闭原则”。
- 过多地使用适配器,会让系统很是零乱,不易总体进行把握。好比,明明看到调用的是A接口,其实内部被适配成了B接口的实现,一个系统若是出现太多这种状况,无异于一场灾难。所以若是不是颇有必要,能够不适用适配器,而是直接对系统进行重构。
- 对于类适配器而言,因为Java至多继承一个类,因此至多只能适配一个适配者类,并且目标类必须是抽象类。
特别声明:一、如若文中有错之处,欢迎大神指出。 二、文章是参考网上一些大神的文章,本身整理出来的,如如有侵权,可联系我删除。