友情支持

如果您觉得这个笔记对您有所帮助,看在D瓜哥码这么多字的辛苦上,请友情支持一下,D瓜哥感激不尽,😜

支付宝

微信

有些打赏的朋友希望可以加个好友,欢迎关注D 瓜哥的微信公众号,这样就可以通过公众号的回复直接给我发信息。

wx jikerizhi

公众号的微信号是: jikerizhi因为众所周知的原因,有时图片加载不出来。 如果图片加载不出来可以直接通过搜索微信号来查找我的公众号。

6. 适配器模式

6.1. 定义

根据 GoF 的著名著作 《设计模式》,适配器模式的定义如下:

适配器模式(Adapter)

将一个类的接口转换成客户希望的另外一个接口。Adapter 模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

— Erich Gamma、Richard Helm、Ralph Johnson、John Vlissides
《设计模式》

6.2. 类图

Diagram

简单地说,就是需要的东西就在面前,但却不能使用,而短时间又无法改造它,于是我们就想办法适配它。

系统的数据和行为都正确,但接口不符时,我们应该考虑用适配器,目的是使控制范围之外的一个原有对象与某个接口匹配。适配器模式主要应用于希望复用一些现存的类,但是接口又与复用环境要求不一致的情况

在GoF的设计模式中,对适配器模式讲了两种类型,类适配器模式和对象适配器模式,由于类适配器模式通过多重继承对一个接口与另一个接口进行匹配,而C#、VB.NET、JAVA等语言都不支持多重继承(C++支持),也就是一个类只有一个父类,所以我们这里主要讲的是对象适配器。

Target(这是客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口)

Adaptee(需要适配的类)

Adapter(通过在内部包装一个Adaptee对象,把源接口转换成目标接口)

在想使用一个已经存在的类,但如果它的接口,也就是它的方法和你的要求不相同时,就应该考虑用适配器模式?

两个类所做的事情相同或相似,但是具有不同的接口时要使用它。

客户代码可以统一调用同一接口就行了,这样应该可以更简单、更直接、更紧凑。

其实用适配器模式也是无奈之举,很有点‘亡羊补牢’的感觉

公司内部,类和方法的命名应该有规范,最好前期就设计好,然后如果真的如你所说,接口不相同时,首先不应该考虑用适配器,而是应该考虑通过重构统一接口。

在双方都不太容易修改的时候再使用适配器模式适配,

DataAdapter用作DataSet和数据源之间的适配器以便检索和保存数据。DataAdapter通过映射Fill(这更改了DataSet中的数据以便与数据源中的数据相匹配)和Update(这更改了数据源中的数据以便与DataSet中的数据相匹配)来提供这一适配器[MSDN]。

代码 47. adapter/Adaptee.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
package com.diguage.didp.adapter;

/**
 * Adaptee 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-19 17:53:33
 */
public class Adaptee {
  public void specificRequest() {
    System.out.println("特殊请求!");
  }
}
代码 48. adapter/Adapter.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package com.diguage.didp.adapter;

/**
 * Adapter 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-19 17:53:33
 */
public class Adapter extends Target {
  private Adaptee adaptee = new Adaptee();

  public void request() {
    adaptee.specificRequest();
  }
}
代码 49. adapter/Client.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package com.diguage.didp.adapter;

/**
 * Client 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-19 17:53:33
 */
public class Client {
  public static void main(String[] args) {
    Target target = new Adapter();
    target.request();
  }
}
代码 50. adapter/Target.java 类
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
package com.diguage.didp.adapter;

/**
 * Target 类
 *
 * @author D瓜哥, https://www.diguage.com/
 * @since 2017-05-19 17:53:33
 */
public class Target {
  public void request() {
    System.out.println("普通请求");
  }
}

6.3. JDK 示例

  1. java.util.Arrays.asList(T…​ a)

  2. java.io.InputStreamReader

  3. java.io.OutputStreamWriter

  4. javax.xml.bind.annotation.adapters.XmlAdapter.marshal(BoundType v) — 在 JDK 17 中已经不存在,应该是在 JDK 9 时被删除。可以在 javax.xml.bind:jaxb-api 中找到。

  5. javax.xml.bind.annotation.adapters.XmlAdapter.unmarshal(ValueType v) — 在 JDK 17 中已经不存在,应该是在 JDK 9 时被删除。可以在 javax.xml.bind:jaxb-api 中找到。