近年來,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(即將推出)
原文點擊標題: