结构模式之适配器模式

视频地址https://www.bilibili.com/video/BV1bt4y1U7YA/

 

适配器模式(Adapter pattern)

1.定义

"Convert the interface of a class into another interface clients expect. Adapter lets classes work together that couldn't otherwise because of incompatible interfaces."
将一个接口转换成客户希望的另一个接口,适配器模式使接口不兼容的那些类可以一起工作

又称包装器(Wrapper),既可以作为类结构型模式,也可以作为对象结构型模式。

使用前提或场景:解决两个已有接口间不兼容问题。Client面向接口编程,而该面向的接口又与第三方接口不兼容,两者又不便于修改,则可用Adapter协调工作

个人理解:不能说是"转换",而是协调不兼容接口间工作。比如客户端期望调用的方法传参是一个样子(面向接口编程,该方法可上升为目标抽象类,下述角色中有提到),而现有第三方实现的满足业务功能的接口可用,但规定的参数格式不一样。但两者(目标抽象类与第三方接口)都不愿或者不能修改,因此,则需要一个适配器来协调两者工作。

2.模式结构

 

示例代码:

public class Adapter implements DataOperation {
    private BinarySearch search;
    private QuickSort sort;

    public Adapter(){
        search = new BinarySearch();
        sort = new QuickSort();
    }
    @Override
    public void sort(int[] array) {
        sort.quickSort(0,array.length-1,array);
    }

    @Override
    public int search(int[] array, int key) {
        return search.BinarySearch(0,array.length-1,key,array);
    }
}

 

public class BinarySearch {

    public int BinarySearch(int low, int high, int key, int[] array){
        if(low>high)
            return -1;
        int mid = (low+high)/2;
        if(array[mid] == key)
            return mid;
        int temp = BinarySearch(low,mid-1,key,array);
        if(temp!=-1) return temp;
        temp = BinarySearch(mid+1,high,key,array);
        if(temp!=-1) return temp;
        return -1;
    }
}
import java.util.Arrays;

/**
 * 客户端面向接口DataOperation编程,具体实例通过IOC或其他随便什么方式注入。
 * 但又有现成的接口可以调用,即:BinarySearch和QuickSort
 * 但两边代码都不想或者不能修改,于是写个Adapter,协调两个接口工作
 */
public class Client {
    public static void main(String[] args){
        DataOperation operation;
        operation = new Adapter();    //此处直接new,只是为了方便.
        int[] ary = {4,1,1,2,1,9,3,2,1,1};
        operation.sort(ary);
        System.out.println(Arrays.toString(ary));
    }
}
public interface DataOperation {
    public void sort(int[] array);
    public int search(int[] array, int key);
}
public class QuickSort {

    public void quickSort(int low, int high, int[] array){
        if(low >= high) //i=low+1 是因为不考虑第一个分界元素
            return;
        int i=low+1,j=high; //i=low+1 是因为不考虑第一个分界元素
        while(i<=j){   //带上"="是因为,当只有两个元素时(即当low+1=high时),会导致不进循环,直接交换
            while(i<=high&&array[i]<=array[low])    //带'='是因为判断最高边界为最后一个元素,i 最后可能会越界,但必然不会发生交换
                i++;
            while(j>low&&array[j]>array[low]) //不带'=',是因为需判断最低边界只有第2个元素。j 可以移到第一个分区元素去,但必然不会发生交换
                j--;
            if(i<j) //即正常情况下
                switchIndex(i,j,array); //数组中交换元素位置的方法
        }
        //结束时,i有3种情况:
        // 1.稳定交换后(ij即将发生交叉后下次),i必定会移到第一个大元素。
        // 2.后面全都比它小,导致i越界1位
        // 3.i也是指向第一个大元素(指向第一个,是因为就算先前有大元素,也肯定已经交换了),但是是因为j发生越界而终止。
        //总之无论哪种,--i都会是最后一个小元素,即分隔元素需要放置的位置
        switchIndex(--i,low,array);
        quickSort(low,i-1,array);   //对分区元素左右两边子数组递归调用此方法
        quickSort(i+1,high,array);
    }
    private void switchIndex(int index1, int index2, int[] array){
        int temp = array[index1];
        array[index1] = array[index2];
        array[index2] = temp;
    }
}

 

包含如下角色:

    1. Target(目标抽象类)
      客户期望的业务接口,可以是具体类,也可以是接口。

    2. Adapter(适配器类)
      适配器类可调用Adaptee接口,以对 Adaptee 和 Target 进行适配,使其协调工作。

    3. Adaptee(适配者类)
      被适配的角色,定义了可工作、已存在、待适配的接口,些情况下甚至没有源代码。

 

      4.Client(客户类)
       客户类面对目标抽象类进行编程

可细分为两种模式:

 

类适配器模式:适配器类与适配者类是继承关系,因为Java不支持多重继承,因此该模式下目标抽象类只能是接口。

对象适配器:适配器类与适配者类是关联关系(也可以称为委派关系),即含有适配者类的成员变量

3.模式扩展

  1. 缺省适配器模式(Default Adapter Pattern):当不需要实现接口提供的全部方法时,可先设计一个抽象类(缺省适配器)来实现该接口,并为每个方法提供一个默认实现(通常是空实现,也称钩子方法[Hook Method]),那么该抽象类的子类(具体业务类)可有选择的只覆盖父类中某些方法来实现需求。
    interface ServiceInterface{
        void M1();
        void M2();
        void M3();
    }
    abstract class AbstractServiceClass implements ServiceInterface{
        public void M1(){}
        public void M2(){}
        public void M3(){}
    }
    class ConcreteServiceClass extends AbstractServiceClass{
        public void M2(){
            System.out.println("具体业务方法");
        }
    }

    2.双向适配器:适配器中同时包含对目标类和适配者类的引用。

4 优缺点

也是其使用场景,可以在不修改客户、适配者、目标抽象类前提下,让几者兼容工作。同时适配器也能很方便的替换,符合开闭原则。

posted @ 2020-04-08 15:36  zw张巍  阅读(202)  评论(0编辑  收藏  举报