适配器模式
概述
将一个接口转换成客户希望的另外一个接口,使得接口不兼容的哪些类可以一起工作。其包名为包装类(Wrapper),适配器模式既可以作为类结构模型,也可以作为对象结构模型。
(1)Targer(目标抽象类)目标抽象类定义在客户所需的接口,可以是一个抽象类、接口或者是具体类。
(2)Adapter(适配器类)适配器调用另外一个接口,作为一个转换器,对Adapter和Target进行适配,适配类是适配器模式的核心,在对象适配器模式中,它通过继承Target并关联一个Adaptee对象,使二者产生关联。
(3)Adaptee(适配者类)适配者即被被适配的角色,它通常定义了一个已经存在的接口,一般作为一个具体类,包含客户需要的业务,由适配器调用。
package com.learn.designmode.mode.adapter;
import netscape.security.Target;
public class Adapter extends Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee){
this.adaptee = adaptee;
}
public void request(){
// 转发具体业务
adaptee.specificRequest();
}
}
完美的解决方案
对象适配器模式
package com.learn.designmode.mode.adapter;
/** 客户端针对此类编程
* @author Administrator
*/
public interface ScoreOperation {
// 排序
public int[] sort(int array[]);
// 查找
public int search(int array[],int key);
}
// 快排业务
class QuickSort {
public int[] quickSort(int[] array,int low,int high) {
if (low < high){
int index = getIndex(array,low,high);
quickSort(array,low,index -1);
quickSort(array,index + 1,high);
}
return array;
}
private int getIndex(int array[], int low, int high){
// 记录基准数据
int temp = array[low];
while (low < high){
// 从尾开始检索,当有数据大于等于基准数据,high--
while (low < high && array[high] >= temp){
high --;
}
// 不满足大于等于,则将当前数据给头部low
array[low] = array[high];
// 再从头部开始检索,当有数据小于等于基准数据,low++
while (low < high && array[low] <= temp){
low ++;
}
// 不满足小于等于,当前数据给尾部high
array[high] = array[low];
}
// 跳出循环,此时的high 和low 相等,
// 将最终的结果给array[high] 也就是给了array[low]
array[low] = temp;
return low;
}
public static void main(String[] args) {
// 测试快速排序
int[] arr = { 49, 38, 65, 97, 23, 22, 76, 1, 5, 8, 2, 0, -1, 22 };
new QuickSort().quickSort(arr,0,arr.length-1);
System.out.println(arr.toString());
}
}
// 二分查找法业务
class BinarySearch {
public int binarySerch(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;
}
}
return -1;
}
}
package com.learn.designmode.mode.adapter;
/** 适配器类
* @author Administrator
*/
public class OperationAdpater implements ScoreOperation {
private BinarySearch binarySearch;
private QuickSort quickSort;
@Override
public int[] sort(int[] array) {
return quickSort.quickSort(array,0,array.length - 1);
}
public OperationAdpater(){
this.quickSort = new QuickSort();
this.binarySearch = new BinarySearch();
}
@Override
public int search(int[] array, int key) {
return binarySearch.binarySerch(array,key);
}
}
package com.learn.designmode.mode.adapter;
import com.learn.designmode.mode.factory.chart.utils.XMLUtil;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
public class Client {
public static void main(String[] args) throws SAXException, IllegalAccessException, IOException, InstantiationException, ParserConfigurationException, ClassNotFoundException {
ScoreOperation scoreOperation = (ScoreOperation) XMLUtil.getBean();
int []socres = {12,13,4,23,123,45,-1,123,34,34,23,67};
int []result;
int sccore;
result = scoreOperation.sort(socres);
for (int item:result){
System.out.println(item);
}
System.out.println();
sccore = scoreOperation.search(socres,12);
System.out.println(sccore);
}
}
类适配器模式
类适配器模式跟对象适配器模式最大的差别在于适配器和适配者是继承关系,如图所示
双向适配器模式
缺省适配器模式
当不想实现一个接口的所有提供方法时,可以使用一个抽象类实现该接口,并提供一个默认的实现方法(空方法),那么该抽象类的子类,可以选择性地覆盖父类的某些方法来实现需求,适用于不想使用一个接口中的所有方法的情况。又称为单接口适配器模式。
(1)ServiceInterface(适配者接口):是一个接口,声明了大量的方法。
(2)AbstractService(缺省适配器类):是缺省适配器模式的核心类,可以使用空方法实现适配器结构的方法,通常为抽象类,对其实例化没有任何意义。
(3)ConcreteService(具体业务类):继承缺省适配器,通过继承缺省适配器,可以有选择性的实现适配者接口的所有方法。
总结:
适配器模式将现有的接口转换为客户所需要的接口,实现了对类的复用,是一种使用频率非常高的设计模式。
优点
(1)目标类与适配器解耦,通过引入一个适配器来重用现有的适配者类,无须更改原有的结构。
(2)增加了类的透明性和复用性,将具体的业务实现过程封装在适配者类中,对于客户是透明的,而且提高了适配者类的复用性,同一个适配者类可以在多个不同的系统中复用。
(3)符合开闭原则,可以在不修改代码的情况下增加新的适配这类
对象适配器还有以下优点
- 一个适配器可以把对个适配者适配到同一个目标
- 可以适配一个适配者的子类,因为适配器与适配者是关联关系,根据里氏替换原则,适配者的子类也可以跟适配器进行适配。
缺点
(1)由于Java不支持多继承,一次最多只能适配一个适配者类,不能同时适配多个适配者。
(2)适配者类不能为最终类,不能为final类。
(3)抽象目标类只能是接口。
对象适配器的缺点
- 与类适配器相比,要在适配器中置换适配者类的某些方法比较麻烦,如果一定要替换适配者类的一个或多个方法,可以先做一个适配者类的子类,在子类中将适配者类的方法置换掉,再把子类当做真正的适配者进行适配,实现较为复杂。
适用场景
(1)系统需要使用一些现有的类,而这些类的接口不符合系统的需要,甚至没有这些类的源代码。
(2)想创建一个可以重复利用的类,用于一些彼此之间没有太大关联的类,包括一些可能在将来引进的类一起工作。