定义:(将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作
类型:结构类型模式
类图:
类的适配器模式(采用继承实现)
对象适配器模式(采用对象组合方式实现)
代码实现:
类的适配器模式
// 已存在的、具有特殊功能、但不符合我们既有的标准接口的类 class Adaptee { public void specificRequest() { System.out.println("被适配类具有 特殊功能..."); } }
// 目标接口,或称为标准接口 interface Target { public void request(); }
// 具体目标类,只提供普通功能 class ConcreteTarget implements Target { public void request() { System.out.println("普通类 具有 普通功能..."); } }
// 适配器类,继承了被适配类,同时实现标准接口 class Adapter extends Adaptee implements Target{ public void request() { super.specificRequest(); } }
// 测试类 public class Client { public static void main(String[] args) { // 使用普通功能类 Target concreteTarget = new ConcreteTarget(); concreteTarget.request(); // 使用特殊功能类,即适配类 Target adapter = new Adapter(); adapter.request(); } }
运行结果:
普通类 具有 普通功能... 被适配类具有 特殊功能...
对象适配器模式
// 适配器类,直接关联被适配类,同时实现标准接口 class Adapter implements Target{ // 直接关联被适配类 private Adaptee adaptee; // 可以通过构造函数传入具体需要适配的被适配类对象 public Adapter (Adaptee adaptee) { this.adaptee = adaptee; } public void request() { // 这里是使用委托的方式完成特殊功能 this.adaptee.specificRequest(); } }
// 测试类 public class Client { public static void main(String[] args) { // 使用普通功能类 Target concreteTarget = new ConcreteTarget(); concreteTarget.request(); // 使用特殊功能类,即适配类, // 需要先创建一个被适配类的对象作为参数 Target adapter = new Adapter(new Adaptee()); adapter.request(); } }
测试结果与上面的一致。
适配器模式的优点:
l 通过适配器,客户端可以调用同一接口,因而对客户端来说是透明的。这样做更简单、更直接、更紧凑。
l 复用了现存的类,解决了现存类和复用环境要求不一致的问题。
l 将目标类和适配者类解耦,通过引入一个适配器类重用现有的适配者类,而无需修改原有代码。
l 一个对象适配器可以把多个不同的适配者类适配到同一个目标,也就是说,同一个适配器可以把适配者类和它的子类都适配到目标接口。
适配器模式的缺点:
l 对于对象适配器来说,更换适配器的实现过程比较复杂。
适用场景:
l 系统需要使用现有的类,而这些类的接口不符合系统的接口。
l 想要建立一个可以重用的类,用于与一些彼此之间没有太大关联的一些类,包括一些可能在将来引进的类一起工作。
l 两个类所做的事情相同或相似,但是具有不同接口的时候。
l 旧的系统开发的类已经实现了一些功能,但是客户端却只能以另外接口的形式访问,但我们不希望手动更改原有类的时候。
l 使用第三方组件,组件接口定义和自己定义的不同,不希望修改自己的接口,但是要使用第三方组件接口的功能。
注意事项:
l 适配器模式最好在详细设计阶段不要考虑它,它不是为了解决还处在开发阶段的问题,而是解决正在服役的项目问题,没有一个系统分析师会在做详细设计的时候考虑使用适配器模式,这个模式使用的主要场景是扩展应用中,就像我们上面的那个例子一样,系统扩展了,不符合原有设计的时候才考虑通过适配器模式减少代码修改带来的风险。
l 再次提醒一点,项目一定要遵守依赖倒置原则和里氏替换原则,否则即使在适合使用适配器的场合下,也会带来非常大的改造。