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