实战适配器模式-兼容接口和属性适配

适配器模式:顾名思义,适配,我们开发时候可能会出现不同属性名称的实体类,但是返回值必须是另一些属性名称的情况,这样其他部门或者前端开发也好不用改动了,这种情况下我们就可以用适配器模式,将原来的实体属性与新的前端需要的返回值的属性进行适配,就能返回期待的返回值。

以下就拿属性适配的例子说明:

我又画了一个丑丑的uml图,大家凑活看一下:

CreateAccount:创建账户实体类
UniteInfo:统一的返回值消息体,我们期望返回的字段
FieldAdapter:将属性消息进行适配的类

 

账户实体类

/*
 *
 * @Author df
 * @Date 2020/10/30 16:59
 */
public class CreateAccount {
    private String number;      // 开户编号
    private String address;     // 开户地
    private Date accountDate;   // 开户时间
    private String desc;        // 开户描述

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Date getAccountDate() {
        return accountDate;
    }

    public void setAccountDate(Date accountDate) {
        this.accountDate = accountDate;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}

统一成我们需要的的实体类

/*
 * 统一的返回值消息体
 * @Author df
 * @Date 2020/10/30 16:03
 */
public class UniteInfo {
    private String userId;
    private String bizId;
    private String bizTime;
    private String desc;

    public String getUserId() {
        return userId;
    }

    public void setUserId(String userId) {
        this.userId = userId;
    }

    public String getBizId() {
        return bizId;
    }

    public void setBizId(String bizId) {
        this.bizId = bizId;
    }

    public String getBizTime() {
        return bizTime;
    }

    public void setBizTime(String bizTime) {
        this.bizTime = bizTime;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}

 重点来了,适配器类,转换成我们需要的实体

/**
 * 属性消息体适配类
 *
 * @Author df
 * @Date 2020/10/30 16:02
 */
public class FieldAdapter {
    public static UniteInfo filter(String strJson, Map<String, String> link) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        return filter(JSON.parseObject(strJson, Map.class), link);
    }

    public static UniteInfo filter(Map obj, Map<String, String> link) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        UniteInfo rebateInfo = new UniteInfo();
        for (String key : link.keySet()) {
            Object val = obj.get(link.get(key));
            UniteInfo.class.getMethod("set" + key.substring(0, 1).toUpperCase() + key.substring(1), String.class)
                    .invoke(rebateInfo, val.toString());
        }
        return rebateInfo;
    }
}

测试一下外部调用:

/*
 * 属性适配例子
 * @Author df
 * @Date 2020/10/30 16:58
 */
public class Test {
    public static void main(String[] args) {
        CreateAccount create_account = new CreateAccount();
        create_account.setNumber("100001");
        create_account.setAddress("北京");
        create_account.setAccountDate(new Date());
        create_account.setDesc("在校开户");
        HashMap<String, String> link01 = new HashMap<String, String>();
        link01.put("userId", "number");
        link01.put("bizId", "number");
        link01.put("bizTime", "accountDate");
        link01.put("desc", "desc");
        try {
            UniteInfo rebateInfo = FieldAdapter.filter(JSON.toJSONString(create_account), link01);
            System.out.println("mq.create_account(适配前)" + JSON.toJSONString(create_account));
            System.out.println("mq.create_account(适配后)" + JSON.toJSONString(rebateInfo));
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

这样就适配成功了,既不会改动原有的任何类和属性,保证原有的类和属性如果还在调用也完全能够使用,这就是适配器的好处,当然如果返回的属性必须改,原有的属性类已经不需要了,那么可以直接将原有的属性改了而不需要适配器方式,看个人需求。

属性方式的适配的例子讲完了,那么接着说说接口适配的例子

接口例子:假如我要调用订单服务中的是否是首单,但是自营接口和自己订单接口起的方法名和返回值都不一样,此时我们就需要适配一下:

IOrderAdapterService: 抽象接口,用来定义统一的返回值和方法名
OrderAdapterServiceImpl: 具体自营适配实现
POPOrderAdapterServiceImpl:POP订单服务适配
OrderService:原自营订单实现
POPOrderService:原pop订单实现

 IOrderAdapterService接口

/*
 * 订单服务
 * Target:目标接口类, 客户所期待的接口, 目标可以是具体的或者抽象的类, 也可以是接口
 * @Author df
 * @Date 2020/11/2 17:10
 */
public interface IOrderAdapterService {
    boolean isFirst(String uId);
}

  OrderAdapterServiceImpl 调用原接口OrderService方式适配

/**
 * 自营订单服务适配,最终返回值是一致的
 * Adapter:通过包装一个需要的支配器对象, 把原来的接口转换成目标接口
 * @Author df
 * @Date 2020/11/2 17:11
 */
public class OrderAdapterServiceImpl implements IOrderAdapterService {
    private OrderService orderService = new OrderService();

    @Override
    public boolean isFirst(String uId) {
        return orderService.isFirstOrder(uId);
    }
}

POPOrderAdapterServiceImpl通过调用POPOrderService方式适配

/**
 * POP订单服务适配,最终返回值是一致的
 * Adapter:通过包装一个需要的支配器对象, 把原来的接口转换成目标接口
 * @Author df
 * @Date 2020/11/2 17:12
 */
public class POPOrderAdapterServiceImpl implements IOrderAdapterService {
    private POPOrderService popOrderService = new POPOrderService();

    @Override
    public boolean isFirst(String uId) {
        return popOrderService.queryUserOrderCount(uId) <= 1;
    }
}

  OrderService是返回boolean

/**
 * 自营:订单各个平台给的方法名不一样,返回值不一样
 * Adaptee:需要适配的类
 * @Author df
 * @Date 2020/11/2 17:08
 */
public class OrderService {
    boolean isFirstOrder(String userId) {
        return true;
    }
}

 POPOrderService是通过查询订单数量判断是不是首单,所以返回long类型

public class POPOrderService {
    Long queryUserOrderCount(String userId) {
        return 1L;
    }
}

 测试一下:

/*
 * 接口适配示例
 * @Author df
 * @Date 2020/11/2 17:17
 */
public class Test {
    public static void main(String[] args) {
        // 通过适配器给接口同一个方法名称并且统一了同一个返回值
        IOrderAdapterService orderAdapterService = new OrderAdapterServiceImpl();
        System.out.println("适配器:判断首单,接口适配(自营)" + orderAdapterService.isFirst("100001"));
        IOrderAdapterService popOrderService = new POPOrderAdapterServiceImpl();
        System.out.println("适配器:判断首单,接口适配(POP)" + popOrderService.isFirst("100001"));
    }
}

以上就是接口适配的示例,设计模式有一些类似语法,比如各个角色啊,必须满足什么条件啊,但是我又记不住就算我现在记下了最终又忘了,按照理解知道怎么写就好,但是也看了下模式结构:

  • Target:目标抽象类 ,客户所期待的接口, 目标可以是具体的或者抽象的类, 也可以是接口,本示例就是IOrderAdapterService
  • Adapter:适配器类,通过包装一个需要的支配器对象, 把原来的接口转换成目标接口,本案例为OrderAdapterServiceImpl和POPOrderAdapterServiceImpl
  • Adaptee:适配者类,需要适配的类,本案例为OrderService和POPOrderService
  • Client:客户类,由谁调用,本案例main方法

本示例学习bugstack设计模式而总结!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值