`

对象转换的问题

阅读更多

 

有句话叫做“计算机科学领域任何问题,都可以间接的通过添加一个中间层来解决”,但是唯一解决不了的问题,是层次本身过多的问题。每一层内都会维护自己在乎的数据对象模型。层与层之间数据的传递,就不可避免地遇到对象类型转换的问题。

这个话题也和最近的项目有关。我们在重构一个老旧的系统,所做的第一件事情,就是要把数据访问层从原有系统中剥离出来,我们精心设计了这一层的模型和结构,但是要让原有系统平缓地从原有数据访问方式上移植到新的数据访问层上,就涉及到上层(Service)的原有数据对象和数据访问层(DAS)之间的数据传递,而二者模型并不相同,而且原有Service的模型并不纯粹,既不是充血模型,model层也掺杂了很多逻辑,因此也不是纯粹的贫血模型,因此这两层之间对象转换的工作就显得尤为重要。

且看这样的对象转换:

public UserNew transform(UserOld old){
    UserNew userNew = new UserNew();
    userNew.setName(old.getName());
    userNew.setAge(old.getAge());
    userNew.setSex(old.getSex());
    userNew.setDesc(old.getDesc());
    ... ...
}
public UserOld transform(UserNew newUser){
    ... ...
}

但是在使用过程中,发现存在着这样一些问题:

  1. 一个UserNew/UserOld对象有40个属性,这样的一次transform就要写40+行这样毫无营养的get/set代码,而再提供一个反向转换的方法这样的代码需要×2;整个系统存在二三十种model,这样啰嗦的转换令人恶心;再者,我们发现,层次可能很多——比如我们在使用一些序列化框架时,需要借由类似的方法将当前对象转换成框架需要的POJO对象,因此一个User就让我们做了很多次这样丑陋的转换。
  2. 转换并不是那么顺利的,经常遇到类型不同的情况,需要经过类型转换或者简单的逻辑处理。比如对于空值的特殊处理,对于0值的特殊处理等。
  3. 转换甚至都不一定是一对一的,特殊情形的处理被迫使用到的逻辑,让整个转换层和业务模块中的很多发生耦合……这不是我希望看到的。

如何思考和解决这样的问题?其实这个问题有很多种表现形式,比如PO-VO对象的互转换等等。这里的争论很多,我整理如下:

1、如果能够尽量保证模型的字段名和和类型一致,可以利用Spring的copyProperties方法来完成POJO对象的拷贝:

BeanUtils.copyProperties(srcObj, desObj);

不过这个方法也有一些缺陷,一个是反射导致的性能损失,一次反射并不明显,对象拷贝可以说是非常频繁的;还有一个是对于一些类型不同的情况,我们需要自定义一些转换逻辑来处理这样的特殊情形。

2、借由一个中间层来承载数据,这样的中间层往往是可序列化的,比如JSON格式,每一种String、int等基础的类型都有转换成JSON的统一处理办法,所有数据的转换都通过通用方法转成JSON格式,然后再根据目标对象对各字段格式的要求,把JSON表示的对象复原。这种办法需要的框架性代码比较多,而且通过序列化对象作为中间介质,不免存在性能损耗的问题,但是对于存在大量数据转换的情况,也不失为一种好办法:

image

3、如果是使用Ruby之类的动态语言,或者变量定义本身就是弱类型的,那么就会省去很多这样转换的工作,当然,由于编译期间对于对象属性的不确定性,也可能引入更多不可预期的运行时异常,或者是一些丢失精度、显示错乱等等这方面的问题。

4、还有一个走极端的方式,对象变成Map<String, String>来存储,这样就免去了对象转换的成本,而且扩展性极强。但是缺点也是极其明显的,这就根本不是面向对象了,这是“面向无差异数据容器”编程……而且缺少约束,对于嵌套场景可读性极差。

5、在某些情况下还有一个变通的方式,我们不减少任何这样对象转换的重复代码,但是,我们可以通过注解、工具等等让这些可预期的代码自动生成,这同样减少了程序员的工作量。

最后,我要说的是,保持模型对象的纯粹和单一性,是减小工程重量的一个原则,让不同层次的逻辑使用同一组对象,虽然可能带来一些契合性问题、兼容性问题,但是带来的好处就是大大减小冗余对象类型的数量,减少这种没有营养的转换。这里又是trade off了。

除了这些,你还有什么体会和好办法?

文章系本人原创,转载请注明作者和出处(http://www.raychase.net

注:本博客已经迁移到个人站点 http://www.raychase.net/ ,欢迎大家访问收藏,本ITEye博客在数日后将不再更新。

 

2
0
分享到:
评论
10 楼 mack 2017-06-14  
一般采用json
9 楼 liaomengge 2015-12-21  
那对比与Apache提供的BeanUils(当然,这仅是对简单地对象,map转化),两者之间的效率差别又有哪些???
8 楼 RayChase 2012-11-12  
一江春水邀明月 写道
RayChase 写道
一江春水邀明月 写道
楼主试过Dozer 或者Orika 这样的工具么?
1. BeanUtils 是不建议用的, 浅拷贝会带来很多对象使用上的陷阱;
2. 中间层Json的转换, 实在不敢恭维, CPU 和内存开销, 性能是硬伤。

没有。谢谢。顺便去学习了一下Dozer和Orika。


可以参考我的博客, http://wangbt5191-hotmail-com.iteye.com/blog/1632444
强烈推荐Orika。 就我的感觉是1.2.0 比较稳定, 但是还是有点小trick 需要绕过去的。 好在它的代码逻辑非常清晰, 很容易看明白

Good!
7 楼 一江春水邀明月 2012-11-12  
RayChase 写道
一江春水邀明月 写道
楼主试过Dozer 或者Orika 这样的工具么?
1. BeanUtils 是不建议用的, 浅拷贝会带来很多对象使用上的陷阱;
2. 中间层Json的转换, 实在不敢恭维, CPU 和内存开销, 性能是硬伤。

没有。谢谢。顺便去学习了一下Dozer和Orika。


可以参考我的博客, http://wangbt5191-hotmail-com.iteye.com/blog/1632444
强烈推荐Orika。 就我的感觉是1.2.0 比较稳定, 但是还是有点小trick 需要绕过去的。 好在它的代码逻辑非常清晰, 很容易看明白
6 楼 RayChase 2012-11-11  
一江春水邀明月 写道
楼主试过Dozer 或者Orika 这样的工具么?
1. BeanUtils 是不建议用的, 浅拷贝会带来很多对象使用上的陷阱;
2. 中间层Json的转换, 实在不敢恭维, CPU 和内存开销, 性能是硬伤。

没有。谢谢。顺便去学习了一下Dozer和Orika。
5 楼 一江春水邀明月 2012-11-11  
楼主试过Dozer 或者Orika 这样的工具么?
1. BeanUtils 是不建议用的, 浅拷贝会带来很多对象使用上的陷阱;
2. 中间层Json的转换, 实在不敢恭维, CPU 和内存开销, 性能是硬伤。
4 楼 RayChase 2012-09-30  
hxze220 写道
我想请问一下,如果用JSON作序列化,由于Java的类型擦除,如何反序列化呢?
比如List<StudentPO>转成JSON是OK的,但是对端由JSON反序列化貌似是会出问题的。
更复杂的还有类属性自引用、类属性是接口或抽象对象、多层集合类嵌套的问题。
另外还想请问下您推荐用哪个JSON包呢?

JSON格式在还原对象的时候是不知道原始类型的。所以这个原始类型信息必须你指定。换言之,模型定义少不了,可以少的是转换的代码。
3 楼 1127 2012-09-30  
有些失望啊,还是没有解决方案。转换这个重复劳动,还是没法避免啊。。。
2 楼 hxze220 2012-09-30  
我想请问一下,如果用JSON作序列化,由于Java的类型擦除,如何反序列化呢?
比如List<StudentPO>转成JSON是OK的,但是对端由JSON反序列化貌似是会出问题的。
更复杂的还有类属性自引用、类属性是接口或抽象对象、多层集合类嵌套的问题。
另外还想请问下您推荐用哪个JSON包呢?
1 楼 jinnianshilongnian 2012-09-29  
引用
保持模型对象的纯粹和单一性,是减小工程重量的一个原则,让不同层次的逻辑使用同一组对象,虽然可能带来一些契合性问题、兼容性问题,但是带来的好处就是大大减小冗余对象类型的数量,减少这种没有营养的转换。这里又是trade off了。



在交换数据及存储数据时 最好采用平台/语言无关形式 如JSON、XML,尽量不要使用平台相关的存储机制,如Java序列化机制。

相关推荐

    Android应用源码之AndroidXstream(解决xml和对象转换问题)_应用.zip

    本篇文章将深入探讨AndroidXstream在Android应用中的使用方法和优势,以及如何解决XML与对象转换问题。 首先,我们需要了解什么是Xstream。Xstream是由Joe Walnes创建的一个开源项目,它提供了Java对象到XML和XML到...

    安卓Android源码——AndroidXstream(解决xml和对象转换问题).zip

    本压缩包"安卓Android源码——AndroidXstream(解决xml和对象转换问题).zip"包含了关于如何在Android项目中使用Xstream来处理XML数据的详细示例和源代码。 Xstream是一个Java库,它能够将Java对象转换为XML,反之...

    Android应用源码之AndroidXstream(解决xml和对象转换问题).rar

    在提供的源码中,"Android应用源码之AndroidXstream(解决xml和对象转换问题)"可能是展示如何在实际的Android项目中集成和使用Xstream的示例。通过下载并研究这些源码,你可以看到如何将Xstream库应用到Android应用的...

    Android应用源码之AndroidXstream(解决xml和对象转换问题).zip项目安卓应用源码下载

    Android应用源码之AndroidXstream(解决xml和对象转换问题).zip项目安卓应用源码下载Android应用源码之AndroidXstream(解决xml和对象转换问题).zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习...

    安卓Android源码——AndroidXstream(解决xml和对象转换问题).rar

    这篇内容将详细讲解AndroidXstream如何解决XML与对象转换的问题。 首先,让我们理解XML序列化和反序列化的概念。序列化是指将Java对象转换为XML字符串,以便于存储或传输。反序列化则是相反的过程,将XML字符串解析...

    Android应用源码之AndroidXstream(解决xml和对象转换问题)-IT计算机-毕业设计.zip

    本项目是一个Android应用源码示例,专注于演示如何使用AndroidXstream来解决XML与Java对象间的转换问题,特别适用于毕业设计和移动应用开发的学习。 首先,AndroidXstream的核心功能是XML绑定。它允许开发者通过...

    java中把对象转化为byte数组的方法.doc

    java中把对象转化为byte数组的方法 Java 中将对象转化为 byte 数组的方法是指将 Java 对象序列化为二进制数据流,以便在网络上传输或存储。这种方法可以应用于各种领域,如分布式计算、网络通信、数据存储等。 在 ...

    php 把对象转化为json

    在PHP中,将对象转换为JSON(JavaScript Object Notation)是一种常见的操作,特别是在与前端交互时,例如在AJAX请求中。JSON格式是轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。下面我们将...

    java实现对象转化为get请求的param参数String字符串

    本人自测非常好用,一般对象可以转化键值对的格式,但是最近项目需要自己手动拼接对象作为get请求的参数,百度了一堆还不如自己写一个,欢迎各位使用,有什么问题提出来哦,一起成长!!!

    C#对象转换类C#对象转换类C#对象转换类

    C#对象转换类C#对象转换类C#对象转换类C#对象转换类C#对象转换类

    对象转换 c++入门知识点

    在C++编程中,对象转换是一项基础且重要的概念,它涉及到类层次结构的处理、多态性和类型安全。本文将深入探讨C++中的对象转换,包括静态类型转换、动态类型转换以及强制类型转换等,旨在为初学者提供一个全面的入门...

    使用json-lib将java对象转换成json字符串

    标题中的“使用json-lib将java对象转换成json字符串”指的是在Java编程中,利用json-lib这个库来将Java对象转化为JSON格式的字符串。JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,广泛用于前后端...

    js中将具有数字属性名的对象转换为数组

    jQuery代码中采用了Array.prototype.slice把这种对象转换为数组,但我试了好几遍,就是不行: 代码如下: var obj = {}; obj[0] = 1; obj[1] = 2; alert&#40;Array.prototype.slice.call(obj&#41;); 上面这段代码在IE...

    javascript对象转换成json

    在JavaScript中,对象转换成JSON(JavaScript Object Notation)是一种常见的数据交换格式,它轻量级、易读、易写,被广泛应用于Web应用程序之间传递数据。JSON格式是基于JavaScript的一个子集,但它并不是...

    xml转对象封装的简单与复杂xml的转化写法

    标题提到的"xml转对象封装的简单与复杂xml的转化写法"主要涉及以下知识点: 1. **JDOM库**:JDOM是Java Document Object Model的缩写,它提供了一种在内存中表示XML文档的方式,通过创建SAXBuilder或DOMBuilder实例...

    json-java对象转换包

    在Java中,为了方便地将Java对象转换为JSON格式以及将JSON字符串解析为Java对象,通常会使用特定的库,如"json-java对象转换包"所提及的json-lib。json-lib是一个Java库,它提供了将Java对象转换为JSON格式,以及将...

    json字符串转换c++类对象

    总的来说,将JSON字符串转换为C++类对象需要选择合适的JSON库,设计类结构来映射JSON键值,解析JSON字符串,并利用库提供的功能将JSON对象转换为C++对象。在实际应用中,还需要注意错误处理和适应各种复杂的JSON结构...

    feature转化为Json对象

    但是在实际应用中,我们需要将 Feature 对象转换为 Json 对象,以便在客户端进行处理和展示。下面,我们将讨论将 Feature 对象转换为 Json 对象的方法和实现。 首先,我们需要了解 Feature 对象的结构。Feature ...

    Android-byte数据序列化成对象对象转化成二进制数据

    本篇将详细介绍如何在Android中将byte数据序列化为对象以及对象转化为二进制数据。 首先,我们需要理解什么是序列化和反序列化。序列化是将一个对象的状态转换为可以存储或传输的形式,通常是二进制数据。反序列化...

    C#将对象数组转换成DataSet使用案例 c#经典案例.pdf

    本文将介绍如何将对象数组转换成DataSet,解决了在ASP.NET 2.0 beta 2开发项目中遇到的问题,即将对象数组绑定到GridView的数据源上,但GridView不支持对象数组的排序,因为GridView的排序功能只支持DataSet类型的...

Global site tag (gtag.js) - Google Analytics