clojure - 当另一个字段更新时更新一个字段的模式的标准实践
问题描述
假设您有两个值x
,并且每次更新时都应该计算y
它们。在 Java 中,一切都是对象,所以我别无选择。这样做的方法是通过一个类,例如y
x
public Data {
private type x, y;
Data(type x) {
this.x = x;
this.y = null;
}
void updateX(type2 val) {
// perform operation to update X
// perform (expensive) operation to update Y
}
void getX() {...}
void getY() {...}
}
在 clojure 中,直接翻译可能使用deftype
and defprotocol
/ definterface
。但这对于仅仅定义两个变量之间的依赖关系来说太过分了。特别是,我反对给它命名并将其与实际类型和协议同等对待。
我知道这就是defrecord
s 的用途——当您需要创建一个不代表业务领域中的实体的类,但defrecord
s 是不可变的。
我还有其他选择吗?我看了看,RxClojure
因为这里的情况似乎是“反应性的”,但这似乎是面向“发射”事件,而不是例如将最新的事件存储在原子中。
解决方案
我不禁认为你想多了。
(def some-var (atom some-value))
(def derived (atom (some-expensive-fn some-var)))
(defn update-derived
[old-state new-state]
(new-state)
(defn update-var
[x]
(swap! derived
update-derived
(swap! some-var (fn [old-state] (x)))))
我们定义了一些状态,一些派生状态,以及一个接受新值并更新两者的函数。
根据评论编辑
如果您希望能够多次执行此操作,您可以使用返回闭包的工厂:
(defn make-stateful-thing-with-derived-value
[init-x-value compute-y]
(let [x (atom init-x-value)
y (atom (compute-y init-x-value))]
(list x
y
(fn [new-x-value]
(swap! y
(fn [old-s] (compute-y new-x-value))
(swap! x (fn [old-s] (new-x-value)))))))
该函数接受一个初始 x 值和一个派生 y 的函数,并返回一个包含原子 x 和 y 的列表以及一个接受值以更新它们的函数。
推荐阅读
- javascript - JSDoc 用于不返回任何内容的方法
- ios - 停止 UIButton 在背景图像更改时调整大小
- mysql - 优化 django 数据库查询
- linux - 无法加载内核模块“elan_i2c_core.ko”
- django - django,团队中的反向查找和具有多对多关系的员工
- mongodb - 试图聚合多个字段 Mongoose
- php - 如何通过 php 将图像下载到我的笔记本电脑路径?
- javascript - Angular CLI 7:Sass 无法编译
- dao - VB5 应用程序在 access2000 mdb 文件上使用 DAO,不时出现 3218 错误
- react-admin - AutocompleteArrayInput 在 2.4.0 中不起作用