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

9.3 完整解决方案

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

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

图9-4 算法库重用结构图

在图9-4中,ScoreOperation接口充当抽象目标,QuickSort和BinarySearch类充当适配者,OperationAdapter充当适配器。完整代码如下所示:

  1. //抽象成绩操作类:目标接口
  2. interface ScoreOperation {
  3. public int[] sort(int array[]); //成绩排序
  4. public int search(int array[],int key); //成绩查找
  5. }
  6. //快速排序类:适配者
  7. class QuickSort {
  8. public int[] quickSort(int array[]) {
  9. sort(array,0,array.length-1);
  10. return array;
  11. }
  12. public void sort(int array[],int p, int r) {
  13. int q=0;
  14. if(p<r) {
  15. q=partition(array,p,r);
  16. sort(array,p,q-1);
  17. sort(array,q+1,r);
  18. }
  19. }
  20. public int partition(int[] a, int p, int r) {
  21. int x=a[r];
  22. int j=p-1;
  23. for (int i=p;i<=r-1;i++) {
  24. if (a[i]<=x) {
  25. j++;
  26. swap(a,j,i);
  27. }
  28. }
  29. swap(a,j+1,r);
  30. return j+1;
  31. }
  32. public void swap(int[] a, int i, int j) {
  33. int t = a[i];
  34. a[i] = a[j];
  35. a[j] = t;
  36. }
  37. }
  38. //二分查找类:适配者
  39. class BinarySearch {
  40. public int binarySearch(int array[],int key) {
  41. int low = 0;
  42. int high = array.length -1;
  43. while(low <= high) {
  44. int mid = (low + high) / 2;
  45. int midVal = array[mid];
  46. if(midVal < key) {
  47. low = mid +1;
  48. }
  49. else if (midVal > key) {
  50. high = mid -1;
  51. }
  52. else {
  53. return 1; //找到元素返回1
  54. }
  55. }
  56. return -1; //未找到元素返回-1
  57. }
  58. }
  59. //操作适配器:适配器
  60. class OperationAdapter implements ScoreOperation {
  61. private QuickSort sortObj; //定义适配者QuickSort对象
  62. private BinarySearch searchObj; //定义适配者BinarySearch对象
  63. public OperationAdapter() {
  64. sortObj = new QuickSort();
  65. searchObj = new BinarySearch();
  66. }
  67. public int[] sort(int array[]) {
  68. return sortObj.quickSort(array); //调用适配者类QuickSort的排序方法
  69. }
  70. public int search(int array[],int key) {
  71. return searchObj.binarySearch(array,key); //调用适配者类BinarySearch的查找方法
  72. }
  73. }

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

类的代码如下所示:

  1. import javax.xml.parsers.*;
  2. import org.w3c.dom.*;
  3. import org.xml.sax.SAXException;
  4. import java.io.*;
  5. class XMLUtil {
  6. //该方法用于从XML配置文件中提取具体类类名,并返回一个实例对象
  7. public static Object getBean() {
  8. try {
  9. //创建文档对象
  10. DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
  11. DocumentBuilder builder = dFactory.newDocumentBuilder();
  12. Document doc;
  13. doc = builder.parse(new File("config.xml"));
  14. //获取包含类名的文本节点
  15. NodeList nl = doc.getElementsByTagName("className");
  16. Node classNode=nl.item(0).getFirstChild();
  17. String cName=classNode.getNodeValue();
  18. //通过类名生成实例对象并将其返回
  19. Class c=Class.forName(cName);
  20. Object obj=c.newInstance();
  21. return obj;
  22. }
  23. catch(Exception e) {
  24. e.printStackTrace();
  25. return null;
  26. }
  27. }
  28. }

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

  1. <?xml version="1.0"?>
  2. <config>
  3. <className>OperationAdapter</className>
  4. </config>

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

  1. class Client {
  2. public static void main(String args[]) {
  3. ScoreOperation operation; //针对抽象目标接口编程
  4. operation = (ScoreOperation)XMLUtil.getBean(); //读取配置文件,反射生成对象
  5. int scores[] = {84,76,50,69,90,91,88,96}; //定义成绩数组
  6. int result[];
  7. int score;
  8. System.out.println("成绩排序结果:");
  9. result = operation.sort(scores);
  10. //遍历输出成绩
  11. for(int i : scores) {
  12. System.out.print(i + ",");
  13. }
  14. System.out.println();
  15. System.out.println("查找成绩90:");
  16. score = operation.search(result,90);
  17. if (score != -1) {
  18. System.out.println("找到成绩90。");
  19. }
  20. else {
  21. System.out.println("没有找到成绩90。");
  22. }
  23. System.out.println("查找成绩92:");
  24. score = operation.search(result,92);
  25. if (score != -1) {
  26. System.out.println("找到成绩92。");
  27. }
  28. else {
  29. System.out.println("没有找到成绩92。");
  30. }
  31. }
  32. }

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

  1. 成绩排序结果:
  2. 50,69,76,84,88,90,91,96,
  3. 查找成绩90
  4. 找到成绩90
  5. 查找成绩92
  6. 没有找到成绩92

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