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

我们先来看一张数据扭转的图,这个是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<T> 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 <R,T> T execute(Class type,R original,Class<T> targetType){
        Assembler assembler = getAssembler(type);
        T target = (T) assembler.convert(original,targetType);
        return target;
    }
}

转换类实现

这里提供一个样例实现,实现接口Assembler,添加返回原始对象和目标对象,实现convert业务逻辑转换,这里有可能要问,里面转换的过程是否还可以优化?可以肯定是可以的,比如用组合模式,把DTO、VO、PO里面的字段进行封装、用组合+接口的方式实现,但是做起来还是比较麻烦。这里最好是建议用get/set方法转换,不要用一些序列化工具转换,执行效率没有get/set高。

/**
 * UserDo  转  UserDto
 */
public class UserDoToUserDtoAssembler implements Assembler<UserDo,UserDto>{
    @Override
    public UserDto convert(UserDo userDo,Class<UserDto> target){
        UserDto userDto = new UserDto();
        userDto.setId(userDo.getId());
        userDto.setName(userDo.getName());
        return userDto;
    }

}

源代码:https://github.com/itrickzhang/spring-demo/tree/master/data-conversion

本文由博客一文多发平台 OpenWrite 发布!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,245评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,749评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,960评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,575评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,668评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,670评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,664评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,422评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,864评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,178评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,340评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,015评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,646评论 3 323
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,265评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,494评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,261评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,206评论 2 352

推荐阅读更多精彩内容