介绍
适配器模式(Adapter Pattern)是一种结构型设计模式,用于将一个类的接口转换成客户端所期望的另一种接口。通过适配器模式,可以将原本不兼容的接口进行适配,使得原本不兼容的类能够一起工作。
适配器模式通常包含以下几个角色:
- 目标接口(Target):定义客户端所需的接口,也是适配器要实现的接口。
- 源接口(Adaptee):定义原本不兼容的接口。
- 适配器(Adapter):将源接口转换成目标接口的类,实现目标接口,同时包含一个源接口的对象。
在适配器模式中,适配器类充当了桥梁的角色,将目标接口和源接口进行连接。适配器类实现了目标接口,同时包含了一个源接口的对象,通过调用源接口的方法来实现目标接口的方法。
适配器模式的优点是可以让原本不兼容的类能够一起工作,同时可以使得客户端代码更加简洁。适配器模式还可以将适配器类和源接口进行解耦,降低了代码的耦合度,提高了代码的可维护性和可复用性。
类适配器和对象适配器
适配器模式有两种实现方式,即类适配器模式和对象适配器模式。
(1) 类适配器模式
类适配器模式通过继承实现源接口的对象,并实现目标接口,最后实现适配。
(2) 对象适配器
对象适配器模式通过拥有被适配对象(关系从继承变成了组合),并实现目标接口,最终实现适配。
代码示例
package com.structural;
/**
* 三孔插座(源接口)转两孔插座(目标接口)
*/
public class AdapterPattern {
// 在客户端代码中,通过目标适配器接口来使用对象
// 对使用者来说,只需要知道适配器提供了一个两孔插座即可,对于适配的细节不需要了解
public static void main(String[] args) {
// 类适配器模式
Target target1 = new ClassAdapter();
target1.doubleHoleSocket();
System.out.println();
// 对象适配器模式
Target target2 = new ObjectAdapter();
target2.doubleHoleSocket();
}
}
/**
* 目标接口(Target),适配器要实现的接口
* 两孔插座
*/
interface Target {
void doubleHoleSocket();
}
/**
* 源接口(Adaptee),原本不兼容的接口
* 三孔插座
*/
interface Adaptee {
/**
* 需要被适配的功能
* 这里用插座转换举例
*/
void threeHoleSocket();
}
/**
* 源接口的实现类
* 实现三孔插座
*/
class AdapteeImpl implements Adaptee {
@Override
public void threeHoleSocket() {
System.out.println("这是一个三孔插座。");
}
}
/**
* 类适配器模式
*/
class ClassAdapter extends AdapteeImpl implements Target {
@Override
public void doubleHoleSocket() {
this.threeHoleSocket();
System.out.println("==========类适配器-开始转换==========");
System.out.println("变成了一个两孔插座。");
}
}
/**
* 对象适配器模式
* 适配器类(Adapter),实现目标接口,并持有源接口的实例
* 通过适配器类来实现目标接口的方法
*/
class ObjectAdapter implements Target {
private Adaptee adaptee;
public ObjectAdapter() {
this.adaptee = new AdapteeImpl();
}
@Override
public void doubleHoleSocket() {
// 调用继承的方法,对其进行适配处理
this.adaptee.threeHoleSocket();
System.out.println("==========对象适配器-开始转换==========");
System.out.println("变成了一个两孔插座。");
}
}
应用场景
(1) 将旧接口适配到新接口
当系统中的某个类使用的是旧的接口,而你希望使用新的接口时,可以使用适配器模式。适配器模式可以将新接口转换为旧接口,使得原本无法协同工作的类能够正常工作。
(2) 统一接口规范
当系统中存在多个具有不同接口规范的类,但你希望它们能够按照统一的接口规范进行操作时,可以使用适配器模式。适配器模式可以将这些类的接口适配为统一的接口规范,使得它们可以互相替换使用。
(3) 包装和转换数据
当需要对数据进行包装、转换或格式化时,可以使用适配器模式。适配器模式可以将数据转换为目标格式,以满足系统的需求。
(4) 解耦客户端和具体实现
当客户端需要与一个具体实现类解耦时,可以使用适配器模式。适配器模式可以将客户端与具体实现解耦,使得客户端只需要与适配器进行交互,而无需直接依赖具体实现。
(5) 兼容多个版本或多个系统
当需要兼容多个版本或多个系统的接口时,可以使用适配器模式。适配器模式可以将不同版本或不同系统的接口适配为统一的接口,使得它们可以共同工作。
总之,适配器模式可以在不修改已有代码的情况下,让原本不兼容的接口能够一起工作,提高了代码的可复用性和可维护性。
优缺点
(1) 优点
- 提供了类之间的透明转换,客户端可以统一通过目标接口与适配器进行交互,而无需关心具体的实现类。
- 可以复用已有的类,通过适配器将其转换为目标接口,无需修改原有代码。
- 解耦性好,客户端与适配器、源接口之间松耦合,一方的变化不会影响到另一方。
(2) 缺点
- 适配器增加了一个额外的间接层,可能导致系统的复杂性增加。
- 某些情况下,适配器需要对源接口的所有方法进行适配,工作量可能较大。
Android中的应用—ListView
在Android中,ListView是一种常用的控件,用于显示列表数据。ListView使用的是对象适配器模式。具体来说,ListView通过适配器对象(Adapter)将数据源适配为ListView所需的视图,从而实现数据的展示。
ListView的适配器可以是BaseAdapter的子类或ArrayAdapter,它们都是通过组合的方式将数据源与ListView进行适配。这里的适配器对象充当了目标接口(ListView所需的接口)和源接口(数据源的接口)之间的桥梁。
适配器对象实现了适配器接口(例如BaseAdapter或ArrayAdapter),并持有数据源的实例。通过重写适配器接口中的方法,适配器对象将数据源的内容适配到ListView的视图中。
下面是在Android中使用适配器模式显示ListView的一般步骤:
- 创建数据源:首先,你需要准备一个数据源,例如一个List或数组,用于存储列表中的数据。
- 创建布局文件:在res/layout目录下创建一个布局文件,用于定义ListView的每个列表项的布局。
- 创建适配器:创建一个继承自BaseAdapter或ArrayAdapter的适配器类,并实现必要的方法。
- 绑定适配器:在Activity或Fragment中找到ListView控件,并将适配器与ListView进行绑定。
代码:略