努力保头发的打工人
努力保头发的打工人
发布于 2021-01-24 / 27 阅读 / 0 评论 / 0 点赞

适配器模式

1 概述

定义 将一个类的接口变换成客户端期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

当我们正常使用一个接口时,如现在手机二级插口都是type-c,现在有了一个圆头插头的耳机,这肯定不能直接使用。我们需要使用一个转换器(适配器)来把圆头转为type-c的插头。代码中也经常会出现类似的问题,下面是适配器模式的通用类图:

适配器模式类图.png

  • Tagert 目标类,我们期望使用的接口,就是上面例子中的type-c

  • adaptee 源角色,耳机圆头插口

  • adapter 适配器

  • 图中写了适配器继承和依赖源角色,这是两种适配器类型,通过继承然后重写方法这种叫作类适配器;通过依赖源角色,这种叫作对象适配器,对象适配器可以同时依赖多个源角色,但java中继承只能继承一个类。一般后者使用较多。

2 优点

  • 适配器可用让两个没有关系的类可以在一起运行,只要适配器可以匹配成功

  • 增加了类的透明性,高层模块只需调用target角色,实现委托给了源角色,这些对高层模块是透明的,也是不需要关心的

  • 提高了复用度 原角色可以在原来系统中继续使用,在目标角色也可以使用。

  • 灵活性好 不用删掉适配器就好,对其他代码没有影响。

3 代码案例

创建目标角色的接口和实现类

/**
 * @author chiangtaol
 * @date 2020-12-07
 * @describe 适配接口, 正在稳定使用的
 */
public interface TargetUser {
​
    /**
     * 获取名字
     * @return /
     */
    String getName();
​
    /**
     * 获取年龄
     * @return /
     */
    int getAge();
​
    /**
     * 获取密码
     * @return /
     */
    String getPassword();
}
​
/**
 * @author chiangtaol
 * @date 2020-12-07
 * @describe 使用中的, 需要被适配的用户信息类
 */
public class TargetUserInfo implements TargetUser {
​
    private String name;
​
    private Integer age;
​
    private String password;
​
    @Override
    public String getName() {
        return name;
    }
​
    @Override
    public int getAge() {
        return age;
    }
​
    @Override
    public String getPassword() {
        return password;
    }
}

创建源角色和实现类

/**
 * @author chiangtaol
 * @date 2020-12-07
 * @describe 新增加的类, 需要适配正在使用中的用户
 */
public interface UserInfo {
​
    Map<String,Object> getBaseUserInfo();
​
}
​
/**
 * @author chiangtaol
 * @date 2020-12-07
 * @describe 新增加的用户信息实现类
 */
public class UserBaseInfo implements UserInfo {
​
    @Override
    public Map<String, Object> getBaseUserInfo() {
        Map<String,Object> map = new HashMap<>();
        map.put("name","张三");
        map.put("age",18);
        map.put("password","111");
        return map;
    }
}

创建适配器,下面分别为类适配器和对象适配器

/**
 * @author chiangtaol
 * @date 2020-12-07
 * @describe 类适配器
 */
public class ClassAdapter extends UserBaseInfo implements TargetUser {
    /**
     * 获取名字
     *
     * @return /
     */
    @Override
    public String getName() {
        return (String) super.getBaseUserInfo().get("name");
    }
​
    /**
     * 获取年龄
     *
     * @return /
     */
    @Override
    public int getAge() {
        return (int) super.getBaseUserInfo().get("age");
    }
​
    /**
     * 获取密码
     *
     * @return /
     */
    @Override
    public String getPassword() {
        return (String) super.getBaseUserInfo().get("password");
    }
}
​
/**
 * @author chiangtaol
 * @date 2020-12-07
 * @describe 对象适配器
 */
public class ObjectAdapter implements TargetUser {
​
    private UserInfo baseInfo;
​
    private Map<String ,Object> map;
​
    public ObjectAdapter(UserInfo baseInfo){
        this.baseInfo = baseInfo;
        this.map = this.baseInfo.getBaseUserInfo();
    }
​
​
    /**
     * 获取名字
     *
     * @return /
     */
    @Override
    public String getName() {
        return (String) this.map.get("name");
    }
​
    /**
     * 获取年龄
     *
     * @return /
     */
    @Override
    public int getAge() {
        return (int) this.map.get("age");
    }
​
    /**
     * 获取密码
     *
     * @return /
     */
    @Override
    public String getPassword() {
        return (String) this.map.get("password");
    }
}

测试代码,第一个是类适配器,第二个为对象适配器,这样源角色就可以充当目标角色使用了

@Test
public void test(){
    TargetUser targetUser = new ClassAdapter();
    String name = targetUser.getName();
    System.out.println(name);
}
​
@Test
public void test1(){
    UserInfo userInfo = new UserBaseInfo();
    TargetUser targetUser = new ObjectAdapter(userInfo);
    String name = targetUser.getName();
    System.out.println(name);
}