一、适配器模式定义:

适配器模式说的是,可以把一个类的接口变换成客户端所期待的另一种接口,使得原本因接口不匹配而无法在一起工作的两个类可以一起工作。

举个例子:比方说我有一个台灯,其插头是标准的两相的交流电插头,即阳极、阴极。我旅游到了一个地方想用自己的台灯,但发现旅馆里面只有三相的插头,即在阳极、阴极的基础上还多了一个地级。这时候怎么办呢,一个两相到三相的转换器(适配器)就能解决这个问题了,而这正是本模式所做的事情。

二、适用场景

1,系统需要使用现有的类,但现有的类却不兼容。 
2,需要建立一个可以重复使用的类,用于一些彼此关系不大的类,并易于扩展,以便于面对将来会出现的类。 
3,需要一个统一的输出接口,但是输入类型却不可预知。

三、模式解释:

Source:需要被适配的类、接口、对象,即Datas。 
Target:需要得到的接口,也就是我们期待得到的接口。 
Adapter:适配器类,协调Source和Target,使两者能够协同工作。

四、代码示例:

先假设系统存在一个现有的类ClassSource:

/**
 * <pre>
 *    @author : orange
 *    @e-mail : 495314527@qq.com
 *    @time   : 2018/9/30 14:46
 *    @desc   : 源类
 *    @version: 1.0
 * </pre>
 */
@Data
public class ClassSource {

    private Map<String, String> baseInfo;

}

正常模式下我们客户端这样去数据:

/**
 * <pre>
 *    @author : orange
 *    @e-mail : 495314527@qq.com
 *    @time   : 2018/9/30 15:01
 *    @desc   :
 *    @version: 1.0
 * </pre>
 */
public class Client {
    public static void main(String[] args){

        //先添加一些数据
        ClassSource classSource = new ClassSource();
        Map<String,String> map = new HashMap<>();
        map.put("name","orange");
        map.put("mobile","110");
        classSource.setBaseInfo(map);


        //客户端取数据
        String name = classSource.getBaseInfo().get("name");
        String mobile = classSource.getBaseInfo().get("mobile");

    }
}

有一天,基于某种原因(也许是业务更改的原因,也许是系统间数据交换的原因等),你需要按照如下接口的方式取数据:

/**
 * <pre>
 *    @author : orange
 *    @e-mail : 495314527@qq.com
 *    @time   : 2018/9/30 14:54
 *    @desc   :目标接口
 *    @version: 1.0
 * </pre>
 */
public interface ClassTarget {

    String getBaseInfoName();

    String getBaseInfoMobile();

}

那么我们就再加一个适配器类,将一个既定的类转换成按照目标接口的所期望的行为形式。

/**
 * <pre>
 *    @author : orange
 *    @e-mail : 495314527@qq.com
 *    @time   : 2018/9/30 14:55
 *    @desc   : 类适配器中的转换器
 *    @version: 1.0
 * </pre>
 */
public class ClassAdapter extends ClassSource implements ClassTarget {

    @Override
    public String getBaseInfoName() {
        return super.getBaseInfo().get("name");
    }

    @Override
    public String getBaseInfoMobile() {
        return super.getBaseInfo().get("mobile");
    }
}

可以由上看出,类适配器模式是指:定义一个类,将一个已经存在的类,转换成目标接口所期望的行为形式。

在具体的实现过程中,又可以基于其实现层次是类层次还是对象层次,将其分为类适配器和对象适配器。如上所写的是类适配器。

对象适配器使用组合代替继承,将源角色类视为适配器角色的属性:

对象适配器:

/**
 * <pre>
 *    @author : orange
 *    @e-mail : 495314527@qq.com
 *    @time   : 2018/9/30 15:06
 *    @desc   : 对象适配器转换器
 *    @version: 1.0
 * </pre>
 */
public class ObjectAdapter implements ClassTarget {

   private ClassSource classSource;

    public ObjectAdapter(){

    }

    public ObjectAdapter(ClassSource classSource){
        this.classSource = classSource;
    }

    @Override
    public String getBaseInfoName() {
        return classSource.getBaseInfo().get("name");
    }

    @Override
    public String getBaseInfoMobile() {
        return classSource.getBaseInfo().get("mobile");
    }
}

 

总结:

适配器模式在JDK中的应用及解读

写了这么多种设计模式了,可能适配器模式是最不好理解的一种写法。适配器模式的写法很多,写法越多、模式越不好理解,就越应该抓住模式的核心,像适配器模式的核心就是"把一个类的接口变换成客户端所期待的另一种接口",所以我们可以看一下InputStreaReader和OutputStreamWriter。

比方说InputStreamReader吧,创建InputStreamReader对象的时候必须在构造函数中传入一个InputStream实例,然后InputStreamReader的作用就是将InputStream适配到Reader。很显然,适配器就是InputStreamReader,源角色就是InputStream代表的实例对象,目标接口就是Reader类。

OutputStreamWriter也是类似的方式。

 

适配器模式的优缺点

优点

1、有更好的复用性。系统需要使用现有的类,但此类接口不符合系统需要,通过适配器模式让这些功能得到很好的复用

2、有更好的扩展性。实现适配器,可以调用自己开发的功能

缺点

过多使用适配器会使得系统非常凌乱,明明调用的是A接口,内部却被适配成了B接口。因此除非必要,不推荐使用适配器,而是直接对系统重构