写点什么

数据

用户头像
顿晓
关注
发布于: 2021 年 05 月 13 日
数据

这次的主题是集合,顺带尝试扩展为数据。

数据的抽象可以分为几个层次:值/常量,类型,复合类型,有限集合,无限集合。


数据建模的关系有 4 种:

1:1,复合类型,如一个人有一个名字

1:N,序列,数组,如一个人有一群朋友

N:1,reduce 如 hash,sum,max,min,stream 化,集合化

N:M,map,图


数据的处理

同步抽象为 iterator,就地执行,

异步抽象为 stream,挂到数据源的 hook 上执行,

针对每个 item 的处理都一样,最佳实践是组合 pipeline,这样的代码修改方便,可维护。

大多数语言的迭代器和流都提供了 pipe 组合的接口,如 map,filter,reduce.


这点要注意的是:

  1. 尽量避免写出大块处理代码,先考虑如何分解

  2. 尽量减少临时变量的使用,临时变量一般可以用增加一个分解步骤解决

  3. 应该完全避免循环外的共享变量,有外部共享/副作用的需要,可以分解为多个 pipe。


数据的抽象

数据/或信息本质是比特,N 比特能表达的信息是 2 的 N 次方,但这对一般的抽象用处不大,只是在优化时有用;

抽象始于人的概念,概念显性化就是类型,所以抽象的最小粒度是类型。

举个例子,人口统计需要人的年龄,该如何抽象?

int age;就犯了个常见的错误,没有把年龄类型化,这时就容易导致一些隐藏的 bug 不能很快暴露出来,比如 age 成负数;以及年龄输入的有效性检测也不能和类型关联;需要单独提供一个函数来做有效性检查,且该函数的归属也难以决策。

class Age { }

class Person { Age age;} 使用类型来组合抽象,则能让代码表达变得很简洁。


如果直接使用原始类型,则可能会导致不能满足需求时变更类型,所以最好封装原始类型,定义能表达需求的自定义类型,让代码更稳定;


对于复合类型,则在自定义类型基础上出现了组合抽象,要考虑 2 件事:

1、组合后的复合类型如何命名

考虑需求当前场景下类型要表达的角色,如同样是人,角色有 Student,Teacher;

2、组合的成员如何选择

只有角色才有动作,才能参与业务逻辑,所以参与逻辑计算的数据就不需要添加进来,如人的年龄,在 Student,Teacher 角色下一般是不需要的。


抽象反模式:

1、复合类型塞了多个角色的成员,当碰到有的逻辑拿到自己不需要的数据,就要考虑抽象的合理性;

一个好的实践是,为每一条逻辑定义自己的角色类型-product type,如果多条逻辑需要聚合在一个对象上,则可以将这多条逻辑对应的 product type 联合(union)成 sum type。


2、类型过于扁平化,疏于类型隔离,导致逻辑容易混用数据,从而导致逻辑也未隔离引发更大的混乱;

好的实践是,增加类型抽象层次,细化抽象粒度,粒度越小,变更影响范围越小,从而整体越稳定。


数据抽象的代价:

总体来说,类型抽象的代价很小,基本都是用代价最小的方式实现,一般是不用考虑;除非遇到计算密集型的情况,需要借助抽象实现的底层细节来做优化。

如原始类型的封包/拆包,数据拷贝/引用。

发布于: 2021 年 05 月 13 日阅读数: 7
用户头像

顿晓

关注

因观黑白愕然悟,顿晓三百六十路。 2017.10.17 加入

视频号「编程日课」 知识星球「俺的死党顶」

评论

发布
暂无评论
数据