Java语义相同但分表存储的地址实体如何复用业务逻辑?
解决方案:基于DTO+泛型复用逻辑的简洁实现
针对你遇到的「同字段多地址实体复用业务逻辑」的问题,核心思路是用通用DTO作为中间数据载体,结合泛型转换工具,把业务逻辑和实体类解耦,无需重复编写代码,也不用大规模重构原有业务。
1. 定义通用地址DTO
先创建一个和AddressEntity字段完全对齐的AddressDTO,作为所有地址业务逻辑的处理载体:
public class AddressDTO { private String province; private String city; private String detail; // 其他和AddressEntity一致的字段、getter/setter }
2. 封装泛型转换工具类
用工具类实现DTO与任意地址实体(DeliveryAddressEntity/BillingAddressEntity)的双向转换,推荐用MapStruct(编译期生成转换代码,性能优于反射工具),也可以用Spring的BeanUtils封装泛型方法:
方式一:MapStruct实现(推荐)
@Mapper(componentModel = "spring") public interface AddressConverter { AddressConverter INSTANCE = Mappers.getMapper(AddressConverter.class); // DTO转配送地址实体 DeliveryAddressEntity dtoToDelivery(AddressDTO dto); // DTO转账单地址实体 BillingAddressEntity dtoToBilling(AddressDTO dto); // 配送地址实体转DTO AddressDTO deliveryToDto(DeliveryAddressEntity entity); // 账单地址实体转DTO AddressDTO billingToDto(BillingAddressEntity entity); }
方式二:BeanUtils泛型封装
public class AddressConvertUtils { @SuppressWarnings("unchecked") public static <T extends AddressEntity> T dtoToEntity(AddressDTO dto, Class<T> entityClass) { try { T entity = entityClass.getDeclaredConstructor().newInstance(); BeanUtils.copyProperties(dto, entity); return entity; } catch (Exception e) { throw new RuntimeException("地址转换失败", e); } } public static AddressDTO entityToDto(AddressEntity entity) { AddressDTO dto = new AddressDTO(); BeanUtils.copyProperties(entity, dto); return dto; } }
3. 改造原有业务逻辑
把原有基于DeliveryAddressEntity的业务逻辑,迁移到基于AddressDTO处理,核心逻辑只写一次:
// 改造前:仅返回DeliveryAddressEntity // public DeliveryAddressEntity convertFromOrder(Order order) { ... } // 改造后:返回通用DTO,核心逻辑复用 public AddressDTO convertFromOrder(Order order) { AddressDTO dto = new AddressDTO(); // 原有赋值逻辑完全复用,只是把对象换成DTO dto.setProvince(order.getProvince()); dto.setCity(order.getCity()); dto.setDetail(order.getAddressDetail()); // ...其他字段赋值 return dto; }
4. 按需转换为目标实体
在需要具体实体的地方,通过转换工具快速得到对应实体:
// 获取配送地址实体 AddressDTO dto = convertFromOrder(order); DeliveryAddressEntity deliveryEntity = AddressConverter.INSTANCE.dtoToDelivery(dto); // 或用BeanUtils工具类:DeliveryAddressEntity deliveryEntity = AddressConvertUtils.dtoToEntity(dto, DeliveryAddressEntity.class); // 获取账单地址实体 BillingAddressEntity billingEntity = AddressConverter.INSTANCE.dtoToBilling(dto); // 或用BeanUtils工具类:BillingAddressEntity billingEntity = AddressConvertUtils.dtoToEntity(dto, BillingAddressEntity.class);
5. 兼容原有业务(可选)
如果不想修改原有调用DeliveryAddressEntity的代码,可以新增重载方法,保留原有接口:
// 保留原有方法,内部复用DTO逻辑 public DeliveryAddressEntity convertFromOrder(Order order) { AddressDTO dto = convertFromOrderToDto(order); return AddressConverter.INSTANCE.dtoToDelivery(dto); } // 新增通用DTO转换方法 public AddressDTO convertFromOrderToDto(Order order) { // 核心业务逻辑写在这里 AddressDTO dto = new AddressDTO(); dto.setProvince(order.getProvince()); // ...其他赋值 return dto; } // 新增账单地址转换方法 public BillingAddressEntity convertFromOrderToBilling(Order order) { AddressDTO dto = convertFromOrderToDto(order); return AddressConverter.INSTANCE.dtoToBilling(dto); }
内容的提问来源于stack exchange,提问作者yorkiepudpud
相关产品推荐
相关产品推荐

