离线下载
PDF版 ePub版

刘伟 · 更新于 2018-11-28 11:00:43

不兼容结构的协调——适配器模式(二)

完整解决方案

Sunny 软件公司开发人员决定使用适配器模式来重用算法库中的算法,其基本结构如图 9-4 所示:

算法库重用结构图

在图中,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[]) {  
return sortObj.quickSort(array); //调用适配者类QuickSort的排序方法
}

    public int search(int array[],int key) {  
return searchObj.binarySearch(array,key); //调用适配者类BinarySearch的查找方法
}
}

为了让系统具备良好的灵活性和可扩展性,我们引入了工具类 XMLUtil 和配置文件,其中,XMLUtil 类的代码如下所示:

import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;
class XMLUtil {
//该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象
    public static Object getBean() {
        try {
            //创建文档对象
            DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = dFactory.newDocumentBuilder();
            Document doc;                           
            doc = builder.parse(new File("config.xml")); 

            //获取包含类名的文本节点
            NodeList nl = doc.getElementsByTagName("className");
            Node classNode=nl.item(0).getFirstChild();
            String cName=classNode.getNodeValue();

            //通过类名生成实例对象并将其返回
            Class c=Class.forName(cName);
            Object obj=c.newInstance();
            return obj;
        }   
        catch(Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

配置文件 config.xml 中存储了适配器类的类名,代码如下所示:

<?xml version="1.0"?>  
<config>  
    <className>OperationAdapter</className>  
</config>  

编写如下客户端测试代码:

class Client {
    public static void main(String args[]) {
        ScoreOperation operation;  //针对抽象目标接口编程
        operation = (ScoreOperation)XMLUtil.getBean(); //读取配置文件,反射生成对象
        int scores[] = {84,76,50,69,90,91,88,96}; //定义成绩数组
        int result[];
        int score;

        System.out.println("成绩排序结果:");
        result = operation.sort(scores);

        //遍历输出成绩
        for(int i : scores) {
            System.out.print(i + ",");
        }
        System.out.println();

        System.out.println("查找成绩90:");
        score = operation.search(result,90);
        if (score != -1) {
            System.out.println("找到成绩90。");
        }
        else {
            System.out.println("没有找到成绩90。");
        }

        System.out.println("查找成绩92:");
        score = operation.search(result,92);
        if (score != -1) {
            System.out.println("找到成绩92。");
        }
        else {
            System.out.println("没有找到成绩92。");
        }
    }
}

编译并运行程序,输出结果如下:

成绩排序结果:
50,69,76,84,88,90,91,96,
查找成绩90:
找到成绩90。
查找成绩92:
没有找到成绩92。

在本实例中使用了对象适配器模式,同时引入了配置文件,将适配器类的类名存储在配置文件中。如果需要使用其他排序算法类和查找算法类,可以增加一个新的适配器类,使用新的适配器来适配新的算法,原有代码无须修改。通过引入配置文件和反射机制,可以在不修改客户端代码的情况下使用新的适配器,无须修改源代码,符合“开闭原则”。