适配器模式(Adapter模式)
在软件设计中也可能出现:需要开发的具有某种业务功能的组件在现有的组件库中已经存在,但它们与当前系统的接口规范不兼容,如果重新开发这些组件成本又很高,这时用适配器模式能很好地解决这些问题。主要是采用的是的继承+构造方法实现
模式的定义与特点适配器模式(Adapter)的定义如下:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。适配器模式分为类结构型模式和对象结构型模式两种,前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。 该模式的主要优点如下。
- 客户端通过适配器可以透明地调用目标接口。
- 复用了现存的类,程序员不需要修改原有代码而重用现有的适配者类。
- 将目标类和适配者类解耦,解决了目标类和适配者类接口不一致的问题。
- 在很多业务场景中符合开闭原则。
其缺点是:
- 适配器编写过程需要结合业务场景全面考虑,可能会增加系统的复杂性。
- 增加代码阅读难度,降低代码可读性,过多使用适配器会使系统代码变得凌乱。
类适配器模式可采用多重继承方式实现,如 C++ 可定义一个适配器类来同时继承当前系统的业务接口和现有组件库中已经存在的组件接口;Java (单继承多实现的一种语言)不支持多继承,但可以定义一个适配器类来实现当前系统的业务接口,同时又继承现有组件库中已经存在的组件。 对象适配器模式可釆用将现有组件库中已经实现的组件引入适配器类中,该类同时实现当前系统的业务接口。现在来介绍它们的基本结构。
类适配器模式的结构图如图 1 所示。:
对象适配器模式的结构图如图 2 所示:
/**
* Copyright (C), 2018-2020
* FileName: AdapterTest
* Author: xjl
* Date: 2020/11/11 16:10
* Description:
*/
package 适配器模式;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class AdapterTest {
/**
* 使用的是v1的提供的入口入参是map类型
* 下一个版本的是支持新的list
*
* @param map
*/
public void forMap(Map map) {
for (int i = 0; i < map.size(); i++) {
String value = (String) map.get(i);
System.out.println("value=" + value);
}
}
//采用适配器的方式 中间使用的是适配器模式
}
//继承的map的接口这说明也会是一个的map的子类
class ListAdapter extends HashMap {
//目标对象新的版本
private List list;
public ListAdapter(List list) {
this.list = list;
}
@Override
public int size() {
return list.size();
}
@Override
public Object get(Object key) {
return list.get(Integer.valueOf(key.toString()).intValue());
}
}
class Test001 {
public static void main(String[] args) {
AdapterTest adapterTest = new AdapterTest();
ArrayList list = new ArrayList();
list.add("庄小焱0");
list.add("庄小焱1");
list.add("庄小焱2");
list.add("庄小焱3");
//使用的适配器的实现转换
ListAdapter listAdapter = new ListAdapter(list);
//可以实现的list类型
adapterTest.forMap(listAdapter);
}
}
模式的应用场景
适配器模式(Adapter)通常适用于以下场景。
- 以前开发的系统存在满足新系统功能需求的类,但其接口同新系统的接口不一致。
- 使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同
适配器模式(Adapter)可扩展为双向适配器模式,双向适配器类既可以把适配者接口转换成目标接口,也可以把目标接口转换成适配者接口,其结构图如图 4 所示。