对象适配器模式
要解决的问题:
没有源码的算法库
YY软件公司在很久以前曾开发了一个算法库,里面包含了一些常用的算法,例如排序算法和查找算法,在进行各类软件开发时经常需要重用该算法库中的算法。在为某学校开发教务管理系统时,开发人员发现需要对学生成绩进行排序和查找,该系统的设计人员已经开发了一个成绩操作接口 ScoreOperation,在该接口中声明了排序方法 sort(int[]) 和查找方法 search(int[], int),为了提高排序和查找的效率,开发人员决定重用算法库中的快速排序算法类 QuickSort 和二分查找算法类 BinarySearch,其中 QuickSort 的 quickSort(int[]) 方法实现了快速排序,BinarySearch 的 binarySearch (int[], int) 方法实现了二分查找。
由于某些原因,现在 Y Y公司开发人员已经找不到该算法库的源代码,无法直接通过复制和粘贴操作来重用其中的代码;部分开发人员已经针对 ScoreOperation 接口编程,如果再要求对该接口进行修改或要求大家直接使用 QuickSort 类和 BinarySearch 类将导致大量代码需要修改。
Sunny 软件公司开发人员面对这个没有源码的算法库,遇到一个幸福而又烦恼的问题:如何在既不修改现有接口又不需要任何算法库代码的基础上能够实现算法库的重用?
通过分析,我们不难得知,现在 Sunny 软件公司面对的问题有点类似本章最开始所提到的电压问题,成绩操作接口 ScoreOperation 好比只支持 20 V 电压的笔记本,而算法库好比 220 V 的家庭用电,这两部分都没有办法再进行修改,而且它们原本是两个完全不相关的结构,如图所示:
现在我们需要 ScoreOperation 接口能够和已有算法库一起工作,让它们在同一个系统中能够兼容,最好的实现方法是增加一个类似电源适配器一样的适配器角色,通过适配器来协调这两个原本不兼容的结构。如何在软件开发中设计和实现适配器是本章我们将要解决的核心问题,下面就让我们正式开始学习这种用于解决不兼容结构问题的适配器模式。
适配器模式可以将一个类的接口和另一个类的接口匹配起来,而无须修改原来的适配者接口和抽象目标类接口。适配器模式定义如下:
适配器模式(Adapter Pattern):将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作,其别名为包装器(Wrapper)。适配器模式既可以作为类结构型模式,也可以作为对象结构型模式。
适配器模式类图表示:
在适配器模式中,我们通过增加一个新的适配器类来解决接口不兼容的问题,使得原本没有任何关系的类可以协同工作。根据适配器类与适配者类的关系不同,适配器模式可分为对象适配器和类适配器两种,在对象适配器模式中,适配器与适配者之间是关联关系;在类适配器模式中,适配器与适配者之间是继承(或实现)关系。在实际开发中,对象适配器的使用频率更高,对象适配器模式结构如图所示:
image.png
在对象适配器模式结构图中包含如下几个角色:
Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。
Target(目标抽象类):目标抽象类定义客户所需接口,可以是一个抽象类或接口,也可以是具体类。
Adapter(适配器类):适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适配器中,它通过继承Target并关联一个Adaptee对象使二者产生联系。
Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类一般是一个具体类,包含了客户希望使用的业务方法,在某些情况下可能没有适配者类的源代码。
根据对象适配器模式结构图,在对象适配器中,客户端需要调用 request() 方法,而适配者类 Adaptee 没有该方法,但是它所提供的 specificRequest() 方法却是客户端所需要的。为了使客户端能够使用适配者类,需要提供一个包装类 Adapter,即适配器类。这个包装类包装了一个适配者的实例,从而将客户端与适配者衔接起来,在适配器的 request() 方法中调用适配者的 specificRequest() 方法。因为适配器类与适配者类是关联关系(也可称之为委派关系),所以这种适配器模式称为对象适配器模式。
2.2 适配器模式详细解决方案(代码层面)
YY软件公司开发人员决定使用适配器模式来重用算法库中的算法,其基本结构如图 9-4 所示:
image.png
在图中,ScoreOperation 接口充当抽象目标,QuickSort 和 BinarySearch 类充当适配者,OperationAdapter 充当适配器。完整代码如下所示:
抽象成绩操作类:目标接口
interface ScoreOperation {
public int[] sort(int array[]); //成绩排序
public int search(int array[],int key); //成绩查找
}
快速排序类:适配者= 被适配的类
class QuickSort {
public int[] quickSort(int array[]) {
sort(array,0,array.length-1);
return array;
}
public void sort(int array[],int p, int r) {
int q=0;
if(p<r) {
q=partition(array,p,r);
sort(array,p,q-1);
sort(array,q+1,r);}
}
public int partition(int[] a, int p, int r) {
int x=a[r];
int j=p-1;
for (int i=p;i<=r-1;i++) {
if (a[i]<=x) {
j++;
swap(a,j,i);}
}
swap(a,j+1,r);return j+1;
}
public void swap(int[] a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
}
二分查找类:适配者=被适配的类
class BinarySearch {
public int binarySearch(int array[],int key) {
int low = 0;
int high = array.length -1;
while(low <= high) {
int mid = (low + high) / 2;
int midVal = array[mid];
if(midVal < key) {
low = mid +1;
}else if (midVal > key) {
high = mid -1;
}else {
return 1; //找到元素返回1}
}
return -1; //未找到元素返回-1}
}
操作适配器:适配器
class OperationAdapter implements ScoreOperation {
private QuickSort sortObj; //定义适配者QuickSort对象private
BinarySearch searchObj; //定义适配者BinarySearch对象
public OperationAdapter() {
sortObj = new QuickSort();
searchObj = new BinarySearch();
}
public int[] sort(int array[]) {
//调用适配者类QuickSort的排序方 法
return sortObj.quickSort(array);
}
public int search(int array[],int key) {
return searchObj.binarySearch(array,key); //调用适配者类BinarySearch的查找方法
}
}
作者:markfork
链接:https://www.jianshu.com/p/b20d7b62ea35