【问题标题】:Java equivalent for knockout.js computed observables?敲除.js 计算的可观察对象的 Java 等价物?
【发布时间】:2016-09-12 06:17:07
【问题描述】:

使用knockout.js computed observables 可以定义一个依赖于其他可观察对象的 JavaScript 可观察对象,使用函数表达式,例如

var computedObservable = ko.computed(function(){ 
    return firtName() + lastName();
});

如果引用的 observable 之一(例如 firstName)发生变化,则计算出的 observable 会自动更新。 引用的 observables 由给定的函数表达式定义,并且不必明确指定

如何在 Java 中实现类似的功能?

(嗯,有JavaFx Bindings,但它们需要显式注册引用的属性/可观察对象。)

我区分两种情况:

a) 使用 Java 分析给定的 lambda 表达式,以自动找出必须考虑哪些引用的 observable。 (引用的可观察对象可能会引用依赖链中的更多可观察对象。) 预期的示例代码:

ComputedObservable<String> computedObservable = new ComputedObservable<>(() -> {
    return firstName.get() + lastName.get();
}); 

b)我必须手动注册每个引用的 observable 才能观察它们。我想避免这种情况。换句话说,我不想拥有类似

的代码
ComputedObservable<String> computedObservable = new CoputedObservable<>();
computedObservable.registerReference(firstName);
computedObservable.registerReference(lastName);
computedObservable.setExpresion(() -> {
        return firstName.get() + lastName.get();
});

或(使用JavaFx Bindings

 DoubleBinding db = new DoubleBinding() { 
        {
            super.bind(a, b, c, d);
        }

        @Override
        protected double computeValue() {
            return (a.get() * b.get()) + (c.get() * d.get());
        }
 };

情况 a) 是否可能,如果是,是否有现有的 Java 实现/库可以这样做?

编辑: 还有一种策略:

c) 使用专用运算符 来定义函数表达式。这些运算符隐式地注册了引用的 observables。因此无需额外的手动注册步骤。 (函数表达式将仅限于可用的运算符,并且可能需要高级功能来实现新的帮助运算符。)

StringBinding fullName = firstName.concat(secondName);
DoubleBinding result = a.multiply(b).add(c.multiply(d)); 

相关问题:

【问题讨论】:

  • 请记住,仅仅因为某些东西在 Javascript 中可能有意义并不意味着您应该尝试将其引入 Java。
  • 您的疑问是否已经反映在我在回答“注册表策略”时提到的缺点中?或者是否还有其他点会使 knockout.js 的方法无用/不适合 Java?
  • 嗯,我的主要观点是,在 Javascript 本身支持类似的东西的地方,Java 中没有类似的机制。这意味着您将努力争取能够以 Javascript 方式编写 Java。这通常表明你做错了什么。就像在 RDBMS 中保存非关系数据一样。
  • 很久以前我在 C# 中做过这个。刚刚将它移植到 Kotlin。还是有兴趣?
  • 我现在更喜欢 JavaScript 编程。由于 ES5... 甚至不再需要 ko 可观察对象...原则上...,因为可以使用 getter/setter 使属性可观察到它们自己。这被 vue.js 使用:vuejs.org/v2/guide/reactivity.html。不过,您的移植可能对 JVM 的其他用户感兴趣。

标签: java reflection lambda binding observable


【解决方案1】:

即使您明确排除了 JavaFX 绑定,我认为它们是最接近的,无需复杂的反射(甚至字节码)黑客攻击。

您的 sn-p 是 Bindings::concat 的模型用例:

ObservableValue<String> firstName = ...;
ObservableValue<String> lastName = ...;
StringExpression name = Bindings.concat(firstName, " ", lastName);

Bindings 定义了大量有用的原子,但可以想象您有更高级的需求,例如a*b + c*d。救援的实用方法!

NumberBinding result = MyBindings.multiplyAndAdd(a, b, c, d);

public NumberBinding multiplyAndAdd(
        ObservableNumberValue a, ObservableNumberValue b,
        ObservableNumberValue c, ObservableNumberValue d) {
    return Bindings.add(Bindings.multiply(a, b), Bindings.multiply(c, d));
}

这不应该满足您的要求吗?

PS:您的 JavaFX 绑定链接指向版本 2 的文档。在研究 JavaFX 时,您应该确保搜索“JavaFX 8”。

【讨论】:

  • 因此,JavaFx 绑定及其专业运算符似乎是我能得到的最好的。专用运算符隐式注册引用的可观察对象并定义函数表达式。 DoubleBinding 结果 = a.multiply(b).add(c.multiply(d)); (我更新了 JavaFx 链接以参考文档的第 8 版。)
【解决方案2】:

也许以下策略也可以,对所有可观察对象使用静态注册表

  • 对给定的 lambda 进行第一次评估。在执行 lambda 表达式时,被引用的 observable 的 get 方法 有一个side effekt:它们告诉注册表它们已被调用。
  • 从注册表中检索引用的 observable 列表。
  • 重置注册表。
  • 将侦听器附加到引用的可观察对象以定义当前更新周期。
  • 重新评估表达式时,还重新创建更新周期

此处更详细地解释了用于淘汰计算 observables 的类似工作流程:

http://knockoutjs.com/documentation/computed-dependency-tracking.html

此策略的

缺点可能是(还有其他缺点吗?):

  • 由于注册开销和更新周期刷新导致性能损失。
  • 可能不适用于多线程(JavaScript 通常在单线程中运行)
  • 单个注册表必须可用于(已知)所有可观察对象。 (在 JavaScript 中,我曾经遇到过一个问题,即对于测试框架,使用了第二个敲除实例。在我注入对测试代码的敲除实例的引用之前,测试代码的 observable 不会与测试代码中的 observable 一起播放.)

优点

  • 计算的 observables 的定义将更直观、更轻便:无需使用/学习专门的运算符,因为所需的所有信息已包含在函数表达式中强>。

【讨论】:

    【解决方案3】:

    我问自己同样的问题,然后我想,为什么不直接实施它。 这是一个非常初稿(还不是线程安全的),这证明它并不难。 我只是在一个小时内把它写下来,但如果我有时间我会改进它。

    https://github.com/t-oster/knockout4j

    【讨论】:

    猜你喜欢
    • 2014-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-19
    相关资源
    最近更新 更多