【问题标题】:In Java, how can I construct a "proxy wrapper" around an object which invokes a method upon changing a property?在 Java 中,如何在更改属性时调用方法的对象周围构造一个“代理包装器”?
【发布时间】:2009-01-23 20:10:03
【问题描述】:

我正在寻找类似于Proxy patternDynamic Proxy Classes 的东西,只是我不想在实际对象上调用方法调用之前拦截它们,而是我想拦截属性正在改变。我希望代理能够表示具有不同属性集的多个对象。 the Proxy class in Action Script 3 之类的就可以了。

一般来说,这是我想要实现的目标:

我有一个线程运行一个对象,该对象管理由程序中其他线程移交的值列表(数字、字符串、对象),因此该类可以负责在磁盘上为检查点应用程序的目的。这个持久化对象管理一个“脏”标志,表示自上一个检查点以来值列表是否已更改,并且需要在它忙于将其写入磁盘时锁定该列表。

持久化器和其他组件通过通用名称识别特定项目,因此在从崩溃中恢复时,其他组件可以首先检查持久化器是否保存了最新的副本,并从中断处继续工作。

在正常操作期间,为了使用他们移交给持久化器的对象,我希望他们接收对代理对象的引用,该代理对象看起来好像是原始对象,但每当他们更改某个值时,持久化者会注意到并采取相应的行动,例如在实际设置实际值之前将项目或列表标记为脏。


编辑:或者,Java 中是否存在通用设置器(如 PHP 5 中的),即如果属性不存在则调用的方法?或者是否有一种类型的对象可以在运行时添加属性?

【问题讨论】:

    标签: java design-patterns proxy-classes


    【解决方案1】:

    如果“属性”是指 JavaBean 属性,即表示一个 getter 和/或 setter 方法,那么您可以使用动态代理来拦截 set 方法。

    如果您的意思是实例变量,那么在 Java 级别上不行。不过,manipulations on the byte code level 或许可以做点什么。

    实际上,最简单的方法可能是使用AspectJ 并定义一个 set() 切入点(它将拦截字节码级别的字段访问)。

    【讨论】:

    • AspectJ 确实是最简单的方法——它不再是纯 Java。
    【解决方案2】:

    您正在寻找的设计模式是:差分执行。我相信。

    How does differential execution work?

    我回答的一个问题与此有关。

    但是,我可以建议您改用回调吗?您将不得不阅读有关此内容的信息,但总体思路是您可以实现在“有趣的事情”发生时激活的接口(通常称为侦听器)。比如改变数据结构。

    必填链接:

    Wiki Differential execution

    Wiki Callback

    好的,这是我看到的答案。差分执行是 O(N) 时间。这真的很合理,但如果这对你不起作用,回调会。回调基本上通过将方法按参数传递给正在更改数组的类来工作。此方法将获取更改的值和项目的位置,通过参数将其传递回“存储类”并适当地更改值。所以,是的,您必须通过方法调用来支持每个更改。

    我现在意识到这不是你想要的。您似乎想要的是一种方法,您可以在数组中的每个变量上提供某种侦听器,当该项目更改时将调用该侦听器。然后侦听器将更改“备份”中的相应数组以反映此更改。

    本来我想不出办法来做到这一点。当然,您可以使用接口创建自己的侦听器和事件。这与回调基本相同,但更好看。

    然后是反射...... Java 有反射,我很肯定你可以用它写一些东西来做到这一点。然而,反射是出了名的缓慢。更不用说编码的痛苦了(在我看来)。

    希望对您有所帮助...

    【讨论】:

    • 这是很有趣的材料,但不是我需要的。差异执行对于我的目的来说太慢了(因为重复的扫描比较),而且我也担心线程问题。只有在数据更改时触发适当的事件时,回调才会有所帮助。
    • 对不起?为什么回调不起作用?我自己做了很多增量生成的事情,而且几乎总是通过回调来完成。
    • 可能我没听懂,但是谁调用回调呢?即,我有一个线程可以更改数据结构,而另一个线程想要对此做出反应。我是否必须在每次更改后进行函数调用,还是可以检测更改并运行回调,例如 onChange 事件处理程序?怎么样?
    • 感谢所有的努力。我现在知道的更多了,虽然我还没有决定要做什么。
    【解决方案3】:

    我不想在调用真实对象之前拦截方法调用,但是 而是我想拦截正在更改的属性

    所以实际上,您要监视的对象不是方便的 bean,而是 C 结构的复兴。我想到的唯一方法是使用Field Access call in JVMTI

    【讨论】:

      【解决方案4】:

      我想自己做同样的事情。我的解决方案是使用使用 Javassist 的动态代理包装器。我将生成一个实现与目标对象的类相同接口的类,将代理类包装在原始类周围,并将代理上的所有方法调用委托给原始类,但也会触发 PropertyChangeEvent 的 setter 除外。

      无论如何,我在我的博客上发布了完整的解释和代码: http://clockwork-fig.blogspot.com/2010/11/javabean-property-change-listener-with.html

      【讨论】:

        猜你喜欢
        • 2018-12-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-09-13
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多