使用适配器模式将异构系统同构化

使用适配器模式将异构系统同构化

适配器模式是一个我们会在不知不觉间使用的模式。

需求

假设本来我们的系统运行良好,已经上线。同时,我们的系统中包含了一个用户模块,可以用来查询用户。项目上线一段时间后,客户要求我们将用户系统对接到客户提供的用户系统上…这,怎么办呢?

用户模块现状

用户服务接口、实现以及我们自己的用户对象

  1. 用户服务接口:
    /**
     * 用户查询Service
     * @author skyline
     */
    public interface IUserService {
    
        /**
         * 通过用户名查询用户
         * @param name
         * @return
         */
        UserDTO getByName(String name);
    
        /**
         * 展示所有用户
         * @return
         */
        List<UserDTO> listAll();
    }
    
  2. 我们自己的用户服务的实现
    /**
     * 我的用户服务
     */
    public class MyUserService implements IUserService{
    
        private final Map<String,UserDTO> userDTOMap;
    
        public MyUserService(){
            userDTOMap = new HashMap<>();
            init();
        }
    
        private void init() {
            UserDTO zhangsan = new UserDTO();
            zhangsan.setAge(18);
            zhangsan.setDept("部门A");
            zhangsan.setName("zhangsan");
            userDTOMap.put("zhangsan", zhangsan);
            UserDTO lisi = new UserDTO();
            lisi.setAge(19);
            lisi.setDept("部门B");
            lisi.setName("lisi");
            userDTOMap.put("lisi", lisi);
            UserDTO wangwu = new UserDTO();
            wangwu.setAge(20);
            wangwu.setDept("部门A");
            wangwu.setName("wangwu");
            userDTOMap.put("wangwu", wangwu);
        }
    
        @Override
        public UserDTO getByName(String name) {
            return userDTOMap.get(name);
        }
    
        @Override
        public List<UserDTO> listAll() {
            return new ArrayList<>(userDTOMap.values());
        }
    }
    
  3. 我们自己的用户对象
    /**
     * 用户对象
     */
    public class UserDTO {
        private String name;
        private Integer age;
        private String dept;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public String getDept() {
            return dept;
        }
    
        public void setDept(String dept) {
            this.dept = dept;
        }
    
        @Override
        public String toString() {
            return "UserDTO{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", dept='" + dept + '\'' +
                    '}';
        }
    }
    

客户新提供的用户接口以及用户对象

  1. 用户新提供的用户服务
    /**
     * 假设这是来自OA sdk的一个类
     * @author skyline
     */
    public class OAUserService {
    
        private final Map<String,OAUserDTO> userDTOMap;
    
        public OAUserService() {
            userDTOMap = new HashMap<>();
            init();
        }
    
        private void init() {
            OAUserDTO zhangsan = new OAUserDTO();
            zhangsan.setAge(18);
            zhangsan.setDeptName("部门A");
            zhangsan.setLoginName("zhangsan");
            userDTOMap.put("zhangsan",zhangsan);
            OAUserDTO lisi = new OAUserDTO();
            lisi.setAge(19);
            lisi.setDeptName("部门B");
            lisi.setLoginName("lisi");
            userDTOMap.put("lisi",lisi);
            OAUserDTO wangwu = new OAUserDTO();
            wangwu.setAge(20);
            wangwu.setDeptName("部门A");
            wangwu.setLoginName("wangwu");
            userDTOMap.put("wangwu",wangwu);
        }
    
        public OAUserDTO queryUser(String userName){
            return userDTOMap.get(userName);
        }
    
        public List<OAUserDTO> getAllUser(){
            return new ArrayList<>(userDTOMap.values());
        }
    }
    
  2. 客户新提供的用户对象
    /**
     * OA用户对象
     */
    public class OAUserDTO {
        private String loginName;
        private Integer age;
        private String deptName;
    
        public String getLoginName() {
            return loginName;
        }
    
        public void setLoginName(String loginName) {
            this.loginName = loginName;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public String getDeptName() {
            return deptName;
        }
    
        public void setDeptName(String deptName) {
            this.deptName = deptName;
        }
    }
    

思考

  1. 这个需求虽然只是改造用户模块,但是由于用户模块会被各种其他模块调用,如果直接将UserDTO以及IUserService 都替换掉,那将会是一个影响巨大的改造,同时将引入极大的不确定性。
  2. 基于上面的考虑,我们需要尽可能的复用UserDTOIUserService
  3. 写一个新的IUserService的实现,来调用客户提供的用户接口OAUserService
  4. 将用户提供的用户对象OAUserDTO想办法转换成UserDTO

改造

提供一个类,将IUserServiceUserDTOOAUserService以及OAUserDTO关联起来。

/**
 * OA用户服务适配器
 * @author skyline
 */
public class OAUserServiceAdapter implements IUserService{
    
    private final OAUserService oaUserService;

    public OAUserServiceAdapter() {
        oaUserService = new OAUserService();
    }

    @Override
    public UserDTO getByName(String name) {
        OAUserDTO oaUserDTO = oaUserService.queryUser(name);
        return convert(oaUserDTO);
    }

    private UserDTO convert(OAUserDTO oaUserDTO) {
        UserDTO userDTO = new UserDTO();
        userDTO.setName(oaUserDTO.getLoginName());
        userDTO.setDept(oaUserDTO.getDeptName());
        userDTO.setAge(oaUserDTO.getAge());
        return userDTO;
    }

    @Override
    public List<UserDTO> listAll() {
        List<OAUserDTO> allUser = oaUserService.getAllUser();
        return allUser.stream().map(this::convert).collect(Collectors.toList());
    }
}

在上面的改造中,OAUserServiceAdapter实现了IUserService接口,但是内部的业务逻辑委托给OAUserService处理,当OAUserService处理完毕后,再通过convert方法将OAUserDTO转换成UserDTO。这样,只要IUserService在实例化时使用OAUserServiceAdapter的实例,系统的用户模块就可以无缝迁移到客户提供的新模块上。

测试

一开始的时候,系统使用内置的用户模块:
使用适配器模式将异构系统同构化
改造完毕后,系统使用客户提供的新模块,但是业务代码却不需要做调整:
使用适配器模式将异构系统同构化

适配器模式

适配器模式是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。

总结

  1. 适配器模式分为类适配器对象适配器,上面的列子中这两种适配器思想都得到了体现。
  2. 适配器模式满足开闭原则,代码改造量小,同时相当灵活。
  3. 过多的使用适配器容易导致系统复杂度上升,同时对象适配器也容易产生非常多的零散对象。
  4. 如果可能的话,从长远来看,适当的对整体系统重构要好于使用适配器模式。
上一篇:Java集合排序


下一篇:IDEA看代码必备插件Call Graph 介绍及使用方法