前言
最近,正在做一个新需求:需要在已有的页面中新增一种与当前数据结构完全不同的数据展示,页面展示基本不变,但后端返回数据结构与这个数据代表的意义完全不同。在产品与UI眼中,这或许并不是什么大的变动,但对程序来说却比较复杂,所有牵扯到的逻辑都需要梳理。(这或许也是产品和研发打架的原因之一)
问题分析
原因
一般小型项目都是 接口 -> 数据库 -> 界面展示
一把梭,只用一个类来定义对象,中间不会经过任何转化和分层。一般来说数据结构很少变,而且多数据类型同一个页面展示的情况大多比较稀少,所以一般都是如此处理的。
解决方法
我这边一般想到几个方法:
直接修改逻辑,增加处理逻辑
这样一般改变逻辑较多,牵扯到逻辑判断的地方都要增加新数据结构的处理。
在已有数据对象中包含新对象
在已有对象中创建一个字段,将新对象注入,改写 get
类型方法,返回新对象的数据,展示到页面上。
这样改动比较简单,但容易发生数据访问问题,需要多测试才行。而且侵入性太强,需要更改已有数据结构,导致逻辑混乱。
复制页面,不同的数据结构访问不同的页面
这种方法只适用于整体数据结构改变的方式,如果是局部异同,则无法解决。而且会增加界面,增加逻辑复杂度,如果界面逻辑更改,则需要两处都进行更改。
提取公共字段,增加抽象层,增加专用展示对象
具体操作其实和直接更改类似,都是需要同样的工作量。而且由于增加了许多兼容性的处理,会导致工作量更大。
好处是,兼容性足够强,再次增加逻辑方便,而且抽象提好了数据层次,对数据结构侵入性没有。
坏处是,之前所有逻辑都需要更改数据结构,添加此层次。
将新对象转化为旧对象
这种方法一般是最容易实现的,但是如果需要进行空字段的处理,同样会增加工作量,比较麻烦。在整体逻辑需要用到某些数据的时候,如果没有此数据,则需要增加专用的处理逻辑。如果需要更改的地方比较少,工作量不太的话,此种方法则是一般情况下大多数人会选择的,但是会导致一些认知混乱,当然如果逻辑本身不复杂的话,一般不会出问题。
DataCache
https://github.com/etby/DataCache
这是一个对象缓存框架,按理说应该是一个对象池。
http://blog.etby.org/2018/03/27/datacache-library/
这是我在写发布这个库的第一个版本之后,写的一篇简单介绍的博客。
应用场景
在做一个应用的时候,经常会遇到各种页面之间数据同步的问题。这个基本是每个APP开发工程中都会遇到的问题,解决方式也是各式各样。
在这里说一下我的方法:
- 使用
DataBinding
- 数据对象全局唯一 ( 使用DataCache库 )
- 在所有外部入口,比如 API、DB 都会设计一层拦截层,在这次获取字段改变,然后直接使用全局唯一对象的
set
方法进行设置,UI 就会自动更新
以上是核心逻辑,在整个应用中保持单个数据只使用一个Java
对象,然后使用DataBinding
框架触发界面更新。( 现在则可以增加LiveData
,使整个过程更流畅)
这个方式并不优美,但是挺好用的。对于掌控整个数据流来说,只需要掌控入口,工作量会小很多。
一些问题
- 由于数据对象有可能循环引用,所以对直接传递对象和序列化有影响,处理起来比较麻烦
- 外部数据更新比较麻烦,对于API,我这边是修改了
Gson
源码来做到自动解析的。 - 性能问题,虽然只用一个对象能够减少内存使用,但更新的时候通知的地方也比较多,有可能会导致性能问题。
DDD 与 DataCache
领域驱动设计虽然之前自己查了很多资料,也看了一些书,但始终不得要领,而且无法进行实际的运用。毕竟增加了许多工作量,我却无法灵活使用,不熟的东西还是不适合使用。
处理上面提到的增加页面数据的问题时,我想到了 DataCache
库,想到了它的优缺点和我现在的窘境,之后想到的 DDD
的分层。对数据结构的分层:VO/PO/DTO
等等。
DDD 的优缺点
- 分层、解耦
- 对逻辑更改的容忍度比较好 ( 只需要在其中一些层进行更改, 这也是所有分层设计都具备的优点 )
- 对数据影响力的限制 ( 应用=数据+算法, 但如果数据的实用性和扩散度太高, 会导致逻辑(算法)被牵制 )
- 穿透性有影响,会影响一些代码的通用性,增加工作量
- 学习和理解起来比较困难
使用 DDD 的一部分
虽然 DDD 比较庞大,但其实我们已经有意无意的使用了类似的思想。比如上面页面问题提出公共数据对象的方式,或者聚合数据对象的方式,都是表现层分层的一种思想,那些对象已经类似VO
了。
我们则可以做的更好,将VO
完全独立出来,然后使用DataCache
将VO
单例化。这样就可以解决多页面的数据同步问题,在逻辑需要用到数据的时候则可以使用真实数据对象来进行操作。这样就可以避开单对象的循环引用的问题,序列化和传递对象则不必太拘束。
逻辑层和展现层使用完全不同的数据结构,当逻辑改变时,则就不需要进行大量的更改,只需要在层与层之间进行一些转化。或许这样做之后,增加的学习成本和工作量则不再是阻碍了。