设计模式之适配器模式

34 阅读3分钟

案例:OA系统人员管理模块

系统设计之初,人员管理模块比较简单,类图如下:

IUserInfo中定义了公司员工的基本信息,CRUD操作都基于这个类来做。

过一段时间后,公司从其他公司借用一批人来支持某个项目,需要把其他公司的员工基本信息也录入公司的OA系统,但是对方的人员基本信息是这样设计的:

员工基本信息分为基本信息、办公信息和家庭信息3类,每个方法返回一个Map,Map中包含具体的信息。

在这种情况下,就可以使用适配器模式对接两个系统:

代码:

/**
 * @Description: 用户基本信息
 */
public interface IUserInfo {

    /**
     * @return 姓名
     */
    String getUserName();

    /**
     * @return 家庭地址
     */
    String getHomeAddress();

    /**
     * @return 手机号码
     */
    public String getMobileNumber();

    /**
     * @return 座机电话
     */
    public String getOfficeTelNumber();

    /**
     * @return 职位
     */
    public String getJobPosition();

    /**
     * @return 家庭电话
     */
    public String getHomeTelNumber();

}

public class UserInfo implements IUserInfo {

    @Override
    public String getUserName() {
        System.out.println("姓名:张三");
        return null;
    }

    @Override
    public String getHomeAddress() {
        System.out.println("家庭住宅:北京市朝阳区幸福路8888号");
        return null;
    }

    @Override
    public String getMobileNumber() {
        System.out.println("手机号:13711112222");
        return null;
    }

    @Override
    public String getOfficeTelNumber() {
        System.out.println("办公电话:010-7654321");
        return null;
    }

    @Override
    public String getJobPosition() {
        System.out.println("职位:销售经理");
        return null;
    }

    @Override
    public String getHomeTelNumber() {
        System.out.println("家庭电话:010-1234567");
        return null;
    }
}

/**
 * @Description: 其他公司的人员
 */
public interface IOuterUser {

    /**
     * @return 基本信息:包括姓名、性别、手机号码
     */
    Map<String, String> getUserBaseInfo();

    /**
     * @return 工作区域信息
     */
    Map<String, String> getUserOfficeInfo();

    /**
     * @return 家庭信息
     */
    Map<String, String> getUserHomeInfo();

}

public class OuterUser implements IOuterUser {

    @Override
    public Map<String, String> getUserBaseInfo() {
        Map<String, String> baseInfoMap = new HashMap<>();
        baseInfoMap.put("userName", "李四");
        baseInfoMap.put("mobileNumber", "18711112222");
        return baseInfoMap;
    }

    @Override
    public Map<String, String> getUserOfficeInfo() {
        Map<String, String> officeInfoMap = new HashMap<>();
        officeInfoMap.put("officeTelNumber", "010-1111111");
        officeInfoMap.put("position", "CTO");
        return officeInfoMap;
    }

    @Override
    public Map<String, String> getUserHomeInfo() {
        Map<String, String> homeInfoMap = new HashMap<>();
        homeInfoMap.put("homeTelNumber", "010-0000000");
        homeInfoMap.put("homeAddress", "广东省深圳市B路2号");
        return homeInfoMap;
    }
}

/**
 * @Description: 适配器
 */
public class OuterUserInfo extends OuterUser implements IUserInfo {

    /**
     * 基本信息
     */
    private Map<String, String> baseInfo = super.getUserBaseInfo();
    /**
     * 家庭信息
     */
    private Map<String, String> homeInfo = super.getUserHomeInfo();
    /**
     * 工作信息
     */
    private Map<String, String> officeInfo = super.getUserOfficeInfo();

    @Override
    public String getUserName() {
        String userName = baseInfo.get("userName");
        System.out.println(userName);
        return userName;
    }

    @Override
    public String getHomeAddress() {
        String homeAddress = homeInfo.get("homeAddress");
        System.out.println(homeAddress);
        return homeAddress;
    }

    @Override
    public String getMobileNumber() {
        String mobileNumber = baseInfo.get("mobileNumber");
        System.out.println(mobileNumber);
        return mobileNumber;
    }

    @Override
    public String getOfficeTelNumber() {
        String officeTelNumber = officeInfo.get("officeTelNumber");
        System.out.println(officeTelNumber);
        return officeTelNumber;
    }

    @Override
    public String getJobPosition() {
        String position = officeInfo.get("position");
        System.out.println(position);
        return position;
    }

    @Override
    public String getHomeTelNumber() {
        String homeTelNumber = homeInfo.get("homeTelNumber");
        System.out.println(homeTelNumber);
        return homeTelNumber;
    }
}

public class App {

    public static void main(String[] args) {

        // 查询本公司员工
        IUserInfo employee1 = new UserInfo();
        employee1.getUserName();

        // 查询外部员工
        IUserInfo employee2 = new OuterUserInfo();
        employee2.getUserName();

    }

}

适配器模式分为两种:

  • 类适配器
  • 对象适配器

以本文的案例为例,对象适配器的修改很简单:

public class OuterUserInfo implements IUserInfo {
    
    private OuterUser outerUser = new OuterUser();
    
    private Map<String, String> baseInfo = outerUser.getUserBaseInfo();
    private Map<String, String> homeInfo = outerUser.getUserHomeInfo();
    private Map<String, String> officeInfo = outerUser.getUserOfficeInfo();
    
    // 其他代码一样
}

适配器模式的通用类图如下:

  • Target是一个接口
  • Adaptee是一个接口
  • 通过Adapter把Adaptee包装成Target的一个子类(实现类)

适配器模式总结:

  • 通过增加业务类的继承关系,解决不同系统对接的问题,通过扩展而不是修改源代码去完成功能实现。
  • 不适合在系统设计阶段采用,没有一个系统分析师会在做详细设计的时候考虑使用适配器模式,这个模式使用的主要场景是在扩展应用中,就像本文的例子一样,当系统扩展了,不符合原有设计的时候才考虑通过适配器模式减少代码修改带来的风险。
  • 适配器模式也称为包装(Wrapper)模式 ,装饰模式也是一种包装模式。

本文原书:《您的设计模式》作者:CBF4LIFE