1. 模式动机
- 在软件开发中采用类似于电源适配器的设计和编码技巧被称为适配器模式
- 通常情况下,客户端可以通过目标类的接口访问它所提供的服务。有时现有的类可以满足客户类的功能需要,但是它所提供的接口不一定是客户类所期望的,这可能是因为现有类中方法名与目标类中定义的方法名不一致等原因所导致。
- 在这种情况下,现有的接口需要转化为客户需要的接口,这样保证了对现有类的重用。如果不进行这样的转化,客户类就不能利用现有类提供的功能,适配器模式可以完成这样的转化。
- 在适配器模式中可以定义一个包装类,包装不兼容接口的对象,这个包装类指的就是适配器(Adapter),它所包装的对象就是适配者(Adaptee),即被适配的类。
2. 模式定义
将一个接口转换为客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构模式,也可以作为对象结构型模式。
3. 模式结构
适配器模式包含如下角色
- Target:目标抽象类
- Adapter:适配器类
- Adaptee:被适配类
-
Client:客户端类
适配器模式有对象适配器和类适配器两种实现
对象适配器:
类适配器:
4. 时序图
5. 代码分析
类适配器:
/**
* 被适配类
*/
public class Adaptee {
public void sampleOperation1(){
System.out.println("被适配类原有方法sampleOperation1()");
}
}
/**
* 目标角色
*/
public interface Target {
/**
* 这是源类Adaptee也有的方法
*/
void sampleOperation1();
/**
* 这是源类Adaptee没有的方法
*/
void sampleOperation2();
}
/**
* 适配者类
*/
public class Adapter extends Adaptee implements Target{
/**
* 由于源类Adaptee没有方法sampleOperation2()
* 因此适配器补充上这个方法
*/
@Override
public void sampleOperation2() {
System.out.println("被适配的sampleOperation2()");
}
}
/**
* 客户端类
*/
public class MainClass {
public static void main(String[] args) {
Target target = new Adapter();
target.sampleOperation1();
target.sampleOperation2();
}
}
对象适配器(只有适配器类有区别,在这里只贴出适配器的代码):
/**
* 适配者类
*/
public class Adapter implements Target {
private Adaptee adaptee = new Adaptee();
@Override
public void sampleOperation1() {
adaptee.sampleOperation1();
}
/**
* 由于源类Adaptee没有方法sampleOperation2()
* 因此适配器补充上这个方法
*/
@Override
public void sampleOperation2() {
System.out.println("被适配的sampleOperation2()");
}
}
运行结果:
6. 优点
- 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。
- 增加了类的透明性和复用性,将具体的实现封装在适配者类中。对于客户端来说是透明的,而且提高了适配者的复用性。
- 灵活性和扩展性都非常好,通过使用配置文件,可以很方便的更换适配器。也可以在不修改原有代码的基础上增加新的适配器类,完全符合“开闭原则”。
类适配器模式还具有如下优点:
由于适配器类是适配者的子类,因此可以在适配器类中置换一些适配者的方法,使得适配器的灵活性更强。
对象适配器模式还具有如下优点:
一个对象适配器可以把多个不同的适配者适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。
7. 缺点
类适配器模式的缺点
对于Java、C#等不支持多重继承的语言,一次最多只能适配一个适配者类,而且目标抽象类只能为抽象类,不能为具体类,其使用有一定的局限性,不能将一个适配者类和它的子类都适配到目标接口。
对象适配器模式的缺点
与类适配器模式相比,要想置换适配者类的方法就不容易。如果一定要置换掉适配者类的一个或多个方法,就只好先做一个适配者类的子类,将适配者类的方法置换掉,然后再把适配者类的子类当做真正的适配者进行适配,实现过程较为复杂。
8. 模式应用
Sun公司在1996年公开了Java语言的数据库连接工具JDBC,JDBC使得Java语言程序能够与数据库连接,并使用SQL语言来查询和操作数据。JDBC给出一个客户端通用的抽象接口,每一个具体数据库引擎(如SQL Server、Oracle、MySQL等)的JDBC驱动软件都是一个介于JDBC接口和数据库引擎接口之间的适配器软件。抽象的JDBC接口和各个数据库引擎API之间都需要相应的适配器软件,这就是为各个不同数据库引擎准备的驱动程序。
参考:图说设计模式