Java面向数据编程1.1版本


近年来,Java 获得了许多新的语言特性:类型模式、switch改进、记录record和记录records模式、密封sealed 类型和一些其他模式。

有时,整体的效果远大于各部分之和,如果正确组合,这些特性可以对我们的日常编码产生重大影响。

过去:面向对象编程
面向对象编程(简称 OOP)可以归结为一句话。它表示一切都可以或(在 OOP 中)应该被建模为状态和行为的组合。实现它的最直接方法是创建将可变状态与操作它们的方法相结合的类。

在 Java 中,OOP这种方法无处不在

因此,我们经常以类似的方式设计自己的系统也就不足为奇了:

在网店中,物品可以用 Item 接口来建模:

  • 该接口由图书(有 ISBN)、家具(有尺寸)和 ElectronicItem(有连接和电池电量的附加信息)等具体类来实现。
  • 该接口有添加到购物车、购买、发货或重新订购等方法。

通过实现新的类,可以很容易地将新的物品类型添加到系统中。

但是......事情往往没那么简单:
虽然将所有这些方法都集中在 Item 上似乎是合理的,因为它们都与购买流程交互,但增加了 predictLowStock(与基于机器学习的预购系统交互)、registerForRecommendations(另一个 ML 系统,这次是物品建议)和 reportPurchase(登记潜在危险物品的购买),让我们怀疑所有这些操作是否真的属于同一个接口。

banq注:这是不同上下文场景的方式,放在Item一个类或接口中肯定不对,如同学生借书,将借书这个动作建模在学生这个类或接口一样,借书时一种具体场景。因此,这里指责面向对象缺点不是OOP本身问题,而是很多人没有意识到场景、上下文BC、界限上下文这个概念的存在,如同在 scope 、 生命周期等都属于上下文概念。

同样有问题的是:

  • 书籍只能显示目录
  • 而 3D 公寓规划器只能处理家具--Item 现在是否应该获得 tableOfContent 和 addToVirtualApartment 方法?
  • 或者,我们可以引入标志或进行 instanceof 检查,

但这并不能解决一段时间后出现的另一个问题:
  • 所有这些子系统都共享 item 实例,
  • 在改变其状态时会反复踩到对方的脚趾,从而导致一些令人不快的 bug。

banq注:这是语言中共享可变状态的问题,而在Rust中避免可变共享状态作为语言的默认已经成功:Rust为何无法成为超级语言? 


不知何故,我们感觉美丽的设计被丑陋的现实打碎了。其中一个关键因素是,OOP 最擅长为不断发展的流程建模,如发货时间、库存管理或推荐系统,但却不太适合为这些流程所运行的事物建模,如上述项目。那么,我们能做些什么呢?

面向数据编程(Data-Oriented Programming:DOP)

  • 面向对象将世界视为一个由相互作用的对象组成的网络,每个对象都具有内部的、通常可变的状态(可能类似于自然生态系统),
  • 而面向数据编程(简称 DOP)将其视为一个系统链,每个系统都具有潜在的变化状态,这些系统对不可变数据进行操作(类似于生产线)。

对不可变数据进行操作?这听起来像函数式编程(简称 FP),事实上 DOP 与它有很多共同之处。但 DOP 还包含可以以面向对象的方式建模的潜在可变系统。

面向数据编程基于许多原则,但其确切表述尚未最终确定。Oracle Java 语言架构师 Brian Goetz 于 2022 年 6 月在其开创性文章《Java 中的面向数据编程》中写道(略作重新排序):

  • 数据是不可变的。
  • 对数据、整个数据以及仅对数据进行建模。
  • 使非法状态无法表达。
  • 在边界处验证。

可以说,这就是 1.0 版。在各种项目(主要是演示和业余项目,但其中一个也在生产中)中使用 DOP 约 18 个月后,我在此提出了第一个修订版本 1.1:

  • 以不可变且透明的方式建模数据。
  • 对数据、整个数据以及仅对数据进行建模。
  • 使非法状态无法表达。
  • 将操作与数据分离。

在接下来的几周内,我们将分别就这四个原则发表一篇文章,并以第六篇文章结束本系列,该文章将面向数据编程置于面向对象和函数式编程的环境中,并就何时何地使用它提供一些指导。

文章系列

  • Java 中的面向数据编程 - 版本 1.1(本文)
  • 不可变且透明地建模数据 - DOP v1.1(即将推出)
  • 对数据、整个数据以及仅对数据进行建模 - DOP v1.1(即将推出)
  • 使非法状态无法表示 - DOP v1.1(即将推出)
  • 将操作与数据分离 - DOP v1.1(即将推出)
  • 完成 DOP v1.1(即将推出)

原文点击标题