专栏名称: SegmentFault思否
SegmentFault (www.sf.gg)开发者社区,是中国年轻开发者喜爱的极客社区,我们为开发者提供最纯粹的技术交流和分享平台。
目录
相关文章推荐
程序员小灰  ·  3个令人惊艳的DeepSeek项目,诞生了! ·  16 小时前  
OSC开源社区  ·  宇树王兴兴早年创业分享引围观 ·  2 天前  
程序猿  ·  “我真的受够了Ubuntu!” ·  2 天前  
程序员的那些事  ·  李彦宏自曝开源真相:从骂“智商税”到送出“史 ... ·  4 天前  
51好读  ›  专栏  ›  SegmentFault思否

项目中频繁的数据转换我们怎么优化

SegmentFault思否  · 公众号  · 程序员  · 2020-02-04 11:45

正文

本文转载于 SegmentFault 社区
作者:itrickzhang


我们先来看一张数据扭转的图,这个是 DDD 思想下各种对象转换的过程。

VO(View Object) :视图对象,用于展示层,它的作用是把某个指定页面 (或组件) 的所有数据封装起来。

DTO(Data Transfer Object) :数据传输对象,用于展示层与服务层之间的数据传输对象。

DO(Domain Object) :领域对象,就是从现实世界中抽象出来的有形或无形的业务实体。

PO(Persistent Object) :持久化对象,它跟持久层 (通常是关系型数据库) 的数据结构形成一一对应的映射关系,如果持久层是关系型数据库,那么,数据表中的每个字段 (或若干个) 就对应 PO 的一个 (或若干个) 属性。


VO 层我们先不看,从 DTO 开始,我们梳理简单一个请求流程中数据会转换几次:

  • 请求时用户接口层 DTO 转 DO
  • 请求时领域层 DO 转 PO
  • 返回时领域层 PO 转 DO
  • 返回是 DO 转 DTO

我们先看下操作之前和操作之后的代码,在来详解:
public static void main(String[] args) {
//初始化对象
UserDto userDto = new UserDto();
userDto.setId(1);
userDto.setName("java圈");
////////////////////////////
//UserDto转成对象UserDo
UserDtoToUserDo userDtoToUserDo = new UserDtoToUserDo();
UserDo userDo = userDtoToUserDo.convert(userDto);
//UserDo转成对象UserPo
UserDoToUserPo userDoToUserPo = new UserDoToUserPo();
UserPo userPo = userDoToUserPo.convert(userDo);
//UserPo转成对象UserDo
UserPoToUserDo userPoToUserDo = new UserPoToUserDo();
UserDo userDo1 = userPoToUserDo.convert(userPo);
//UserDo转成对象UserDto
UserDoToUserDto userDoToUserDto = new UserDoToUserDto();
UserDto userDto1 = userDoToUserDto.convert(userDo1);
System.out.println("改造之前的结果:"+userDto1);

////////////////////////////
UserDo userDo2 = AssemblerFactory.getInstance().execute(UserDtoToUserDoAssembler.class,userDto, UserDo.class);
UserPo userPo1 = AssemblerFactory.getInstance().execute(UserDoToUserPoAssembler.class,userDo2, UserPo.class);
UserDo userDo3 = AssemblerFactory.getInstance().execute(UserPoToUserDoAssembler.class,userPo1, UserDo.class);
UserDto userDto2 = AssemblerFactory.getInstance().execute(UserDoToUserDtoAssembler.class,userDo3, UserDto.class);
System.out.println("改造之后的结果:"+userDto2);

}
这段代码用两种方式实现了上述的四个对象的转换:

第一种

  • 直接通过创建对象的方式进行数据扭转,可读性较差,容易混乱;
  • 创建流程较麻烦,需要创建 8 个对象,占用额外的内存空间
  • 可扩展性较差,牵一发而动全身;

第二种

  • 通过工厂模式+代码模式+单例模式设计思想去实现,符合 SOLID 原则;
  • 基于接口做实现代理,符合低耦合的概念;
  • 可读性较强,每一个转换只要一行代码,只要清楚转换类型、原始对象和目标对象




功能实现



接口定义


数据转换接口,里面有一个 convert 转换的方法,需要传入原始对象,和返回对象的类型,直接返回目标对象,便于代码规范化话和代码隔离。
public interface Assembler<R,T> {
public T convert(R original,Class targetType);
}


工厂类定义


AssemblerFactory 是一个单例工厂,通过 getAssembler 传入的类型,获取目标转换对象的实例, ReflectionUtils Spring-core 里面的反射方法; execute 执行实现类连的转换方法,需要传入原始对象和目标对象。
public class AssemblerFactory {
private static AssemblerFactory INSTANCE = new AssemblerFactory();

private AssemblerFactory(){}

public static AssemblerFactory getInstance(){
return INSTANCE;
}

private Assembler getAssembler(Class type){
Assembler assembler = null;
try {
assembler = (Assembler) ReflectionUtils.accessibleConstructor(type, new Class[0]).newInstance(new Object[0]);
} catch (Throwable e){
e.printStackTrace();
}
return assembler;
}

public T execute(Class type,R original,Class targetType){
Assembler assembler = getAssembler(type);
T target = (T) assembler.convert(original,targetType);
return target;
}
}


转换类实现


这里提供一个样例实现,实现接口






请到「今天看啥」查看全文