knock等效于knockout.js计算的observables?

时间:2016-05-16 12:45:30

标签: java reflection lambda binding observable

使用knockout.js computed observables,可以使用函数表达式定义依赖于其他observable的JavaScript observable,例如

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

如果其中一个引用的observable(例如firstName)发生更改,则会自动更新计算的observable。 引用的observables 由给定的函数表达式定义,不必明确指定

如何在Java中实现类似的东西?

(嗯,有JavaFx Bindings,但它们需要显式注册引用的属性/ observables。)

我区分了两种情况:

a)使用Java分析给定的lambda表达式,自动找出必须考虑哪些引用的observable 。 (引用的observable可能会引用依赖链中的其他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)使用专用运算符来定义函数表达式。这些运算符隐式注册引用的observable。因此,无需额外的手动注册步骤。 (函数表达式将仅限于可用的运算符,并且可能需要高级功能来实现新的帮助运算符。)

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

相关问题:

3 个答案:

答案 0 :(得分:1)

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

您的代码段是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的文档。您应该确保搜索&#34; JavaFX 8&#34;在研究JavaFX时。

答案 1 :(得分:0)

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

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

此处更详细地解释了淘汰计算可观测量的类似工作流程:

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

这个策略的

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

  • 由于注册开销和更新周期更新导致性能丢失。
  • 使用多线程可能效果不佳(JavaScript通常在单个线程中运行)
  • 单个注册表必须可用于(已知)所有可观察对象。 (在JavaScript中我曾遇到过这样的问题:对于测试框架,已经使用了第二个knockout实例。测试代码observable与测试代码中的observable一起使用,直到我注入对测试代码的knockout实例的引用。)

<强>赞成

  • 计算的可观察量的定义将更直观,更轻松:无需使用/学习专业运算符,因为所需的所有信息已包含在函数表达式中

答案 2 :(得分:0)

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

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