Tumax-H5数据流向及解析

Tumax-H5数据流向及解析

说明

相信很多  同事在刚刚接触图满意项目时,对项目中的数据流向和数据解析过程都很模糊, 不清楚数据到底是如何从一份 JSON 数据变为我们使用的数据对象。

这篇文章将会为你  介绍图满意项目中,数据的解析还原及数据流向,为你揭开这一神秘面纱。

通过这篇文章,你将会明白数据是如何通过接口返回的 JSON 一步步变为我们可以拿来使用的 Model,同时我会介绍为什么需要这样处理,如果不这样处理带来的  弊端是什么。

 当阅读完文章后,需要对图满意项目有明确的数据流向认知,清晰  明了的了解 dataObject、ModelData 及 Model 的区别。后续开发业务代码需要明确  认知代码应该存放的位置。避免将代码放到不同阶段的类中,出现后期  不可维护、难以修改的情况。

数据解析流向

首先,需要明确理解这张图,这张图中已经描述了我们对整个 Home 数据的解析、实现过程。我先来介绍一下图中出现的 3 种类型的类分别代表什么。

  1. 原始数据:JSON, 意思就是可被序列化的 JSON 数据,数据中用到需要保存、传输时的最终结果。
  2. Data 类:用于将 JSON 数据转为实体类的中间  类,所有对数据的解析、转换、适配都在这种类中处理。
  3. 实体类:在项目中真正用到的数据类型,也就是数据 Model。

我分别详细解释一下这 3 种类的典型事例及作用:

原始数据

比如一份楼层数据:

{
  "id": "10",
  "name": null,
  "height": 2734.4058001657,
  "isMirror": false,
  "offset": {
    "x": 0,
    "y": 0
  },
  "pictureId": "20190115104131777061547519673942",
  "pictureType": 1,
  "totalClearArea": 29.01560021174,
  "uesGuideline": false,
  "useComstomLighting": true,
  "useIESLight": true,
  "compassRotation": 1.1699375695728,
  "areaIds": [],
  "switchIds": [],
  "scale": 1,
  "holes": [],
  "lightH5VIewIds": [],
  "ceilingIds": [],
  "bgWallIds": [],
  "parquetIds": [],
  "bkShapeTexturesIDs": [],
  "walls": [
      ...
   ],
  "curvedWalls": [
      ...
  ],
  "rooms": [
      ...
  ],
  "corners": [
      ...
  ],
  "pillars": [],
  "ceilings": [],
  "parquets": [],
  "bgWalls": [],
  "lightViews": [],
  "lightH5Views": [],
  "layoutGroups": [],
  "layoutModels": [],
  "holeTextureIDs": [],
  "floorTextureIDs": [
    ...
  ],
  "wallTextureIDs": [
    ...
  ],
  "pillarTextureIDs": [],
  "ceilingTextureIDs": [],
  "parquetTexturesID": []
}

在这份数据中可以看出,该数据可以被序列化来传输,并且在数据中会包含很多嵌套的基础数据,如 Wall,Corner 等。

Data 类

如 ModelData,WallData,CornerData

在 Data 类中,会实现以下几个基础方法: 

  • build() 用于将实体类转为 Data类
  • rebuild() 用于将Data类转为实体类
  • extractToData() 用于将原始数据转为Data类
  • buildData() 用于将Data 类转为原始数据

Data 类主要会处理数据解析的各类内容对于一些父级的 Data 类,比如 HomeData,LevelData 可以调用其他子级 Data 类,用于协调解析其他基础内容。

Data 类中同样会处理一些适配内容,比如流程图中出现的 LevelAdapter。就是因为随着业务的不断发展,可能会更改原始数据的数据结构。原有的 Home 数据是一整体的,无法做到对单个楼层保存、序列化等处理。为了实现对单独楼层的序列化处理,我们需要将原有数据做一层处理,处理为所需要的原始数据,交给 LevelData 处理解析,避免 HomeData 直接解析 Level 中的数据。

类似的还有处理 Flash 的一些适配数据,如 CurvedAdapter、RectWindowAdapter 等,都是用于处理一些不好解释的数据。

需要注意的一点是:Adapter 的使用要遵循在  源头及末尾处理,切勿在解析过程中处理,比如 Flash 的 z、y 坐标轴与 H5 的坐标轴刚好相反,处理这类数据一定要在解析的源头处(还未变成 Data 类的时候处理),切勿在 Data 解析为实体类的时候再处理这类  数据。同样的,在输出时做数据适配还原也一定要在数据  已经解析成为原始数据后  再走适配逻辑,切勿直接修改 Data 类做  相关适配,后患无穷。

实体类

如 Home,Level, Model, Wall, Corner

真正在项目中使用最多的数据对象,通过操作数据对象可以同步修改  视图内容及  页面的属性面板(DOM)。

数据对象可以看做一个大的状态管理池,数据对象中存在大量关联关系,如墙体(Wall)中可能关联挂墙模型(Models),墙体(Wall)中可能关联墙角(Corners), 墙角(Corner)中可能关联多个墙(Walls)。

数据对象本身就是一个发布者。 遵循观察者模式,数据对象通过 Mobx 本身可以当做一个发布者,关键数据改变将会触发通知订阅这些关键数据的对象。比如 Model.position.x 改变,Model3D\Model2D 在实例化的时候会订阅这些关键数据。那么,position.x 改变将会通知到对应数据做到实时更新改变。

注意:

上述内容中,我们在方便的使用了各种关联、订阅后,也同样可能会留下很多“后遗症”。

比如 Wall 关联了 Corner,那么 Corner 在销毁的时候就需要一定处理  他与 Wall 之间的关联,否则 JS 的垃圾回收机制并不会将这部分内容销毁。

再比如 Model2D 中订阅了很多 Model 关键数据的内容,那么在 Model 的发布池(_events)中就会存在 Model2D 的引用,如果 Model2D 在销毁的时候没有  处理释放这些订阅,他们之间的关联就会一直存在。那么如果来回切换几次楼层,这种后果不可想象。

所以在使用到 Mobx,EventEmit(on,emit),相互关联时,一定要意识到销毁的时候如何处理,多想一步。

上述内容中会吧所有的订阅返回丢入this._disposeArr中,这样在基类的 destroy 中,就会处理引用关系了。

常见需求点处理方法

将某个实体类,单独做序列化

我们上面的流程图是按照整个户型数据的维度来看,但是在很多时候,我们可能需要的是将某个基础实体类(Model,Group,Hole)单独处理为序列化的原始数据,或者从 SideBar 中的原始数据单独处理为实体类。

遇到这类情况需要思考的第一思路就是  借助 Data 类,保证 Data 类的四个基础方法是实现并且可以用的,那么整体数据就已经可以实现。

如果发现实现过程中出现数据不统一,户型数据中的解析字段与其他过程的解析字段不同, 尽量借助适配器(Adapter)转换解析字段,保证 Data 类解析过程尽量统一。这样做的好处是后续如果对解析过程中有修改,或者  增加字段等能够做到错误最小, 耦合性最低。

切勿单独再写一套解析方法,这样很容易导致后续一个  实体类的数据变动引起解析保存失败等严重事故。

数据中需要增加一个字段,该如何做

在不断的迭代中,可能会出现需要对某个实体类的原始数据做字段增加,此时应该如何处理这类需求。

其实在了解了整体的  数据解析流向后,这类需求自然应该迎刃而解。

首先应当在对于的 Data 类中建立对应解析字段,然后分别实现 4 个基础方法动作中对数据的处理步骤。在最终的序列化数据中就已经出现了。

某一部分数据与新版本数据不适配

首先需要确定是,这份数据是否是完整的。完整的意思就是, 关键性数据还是存在的,只是数据  保存的格式与原来数据不适配。

若非完整数据,则根据metaData.compatibilityVersion最低向下兼容版本,提示数据不兼容异常 。

若完整数据,那么就需要做适配器处理。但有些数据是不需要做保存适配的,也就是数据这样解析后,不需要在保存的时候对数据做原始转换(比如:弧形墙),这类适配就只需要做单向适配。而有些数据的适配是需要在保存的时候依然转换回之前的数据格式,这就需要分别实现 in、out 两种方式

持续优化

  • 对 Data 类实现基础接口IDataExtract
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×