【问题标题】:Any easy way to override method for existing object at runtime在运行时覆盖现有对象的方法的任何简单方法
【发布时间】:2014-03-12 04:52:34
【问题描述】:

假设我有一个域对象,这是伪代码

public class SampleClass {
  id
  title
  ... a lot of other fields from database
  public boolean equals(AnotherObj) {
       return this.id.equals(AnotherObj.id);
  }
}

equals 方法是基于 id 的,适用于大多数场景。但在一种情况下,如果标题相同,则两个对象应被视为相等。 对象放在list和list.contains(obj)中,list.indexOf(obj)被大量调用用于业务逻辑,这取决于equals方法。

如何在运行时重写equals方法? sampleClass 对象可能包含复杂的子树,我不想将它复制到内存中。

我想为现有对象创建一个包装器。包装器仅包含特定的 equals 方法,所有其他方法调用仍应传递给现有对象。

我查看了 cglib,但它必须自己生成目标对象,它不能包装现有对象。

有什么简单的方法吗?

【问题讨论】:

  • 危险:这不是 Object.equals() 你在这里覆盖
  • 您想在大多数情况下实现proxy pattern 并传递对代理对象的调用,但根据代理对象的底层类做一些不同的事情?
  • 我知道这不是对象的平等。这就是为什么我只想将特定的 equal 放在包装器中。
  • 当您将自己复杂到这种程度时,它会告诉您您正在寻找解决方案的错误位置。
  • 那看我的回答;需要番石榴,但番石榴是金矿

标签: java object runtime overriding


【解决方案1】:

假设您实际上是在谈论 Object.equals()/.hashCode(),这不是您的代码当前所做的,您可以使用 Guava 的 Equivalence 来做到这一点。

创建一个等价物:

public final class SampleClassIdEquivalence
    extends Equivalence<SampleClass>
{
    // override .doEquivalent(), .doHash()
}

那么你可以这样使用它:

final Equivalence<SampleClass> byId = new SampleClassIdEquivalence();

byId.equivalent(o1, o2);

Set<Equivalence.Wrapper<SampleClass>> set = ...

set.add(byId.wrap(whatever));

然后您可以通过名称或其他方式为相等创建其他等价;你的选择。

事实上,Equivalence.equals()/.hashCode() 差不多,就像 ComparatorComparable 一样。

【讨论】:

  • 谢谢,这是一种解决方案。我想我需要覆盖 wrap 方法来让我取回被包装的原始类。奇怪的是,guava API 不提供。
  • 哦,查看Wrapper类的api后发现get()方法可以返回被包装的原始对象。谢谢
【解决方案2】:

我不会尝试包装这些对象,而是修改该类,以便它了解在其equals 方法中应该检查的内容(在每种情况下)。然后在这种特殊情况下,只需设置告诉对象equals 应该如何工作的任何状态成员(或任何状态成员)。请确保不要违反合同。

我还建议实际覆盖Object#equals(例如,确保您的equals 接受Object,而不仅仅是AnotherObj)。 (当然,和往常一样,hashCode 也是如此。)

但是如果你确实想这样做,并且你想用equals 来做,这听起来像是the Facade pattern 的工作这在Java 中有点痛苦:你有在构造函数中创建另一个接受对象作为参数的整个类,通过仅在对象上调用它们来实现除equals 之外的所有方法,然后(当然)以不同的方式实现equals

所以基本上:

class SampleSubclass extends SampleClass {
    SampleClass inst;

    SampleSubclass(SampleClass inst) {
        this.inst = inst;
    }

    @override
    String someMethod() {
        return inst.someMethod();
    }

    // ...and so on...

    @override
    public boolean equals(AnotherObj other) { // <== But this really should accept Object, not AnotherObj
        // ... implementation...
    }
}

【讨论】:

  • 我也考虑过这个解决方案。在需要特定的相等逻辑之前,我需要 setState,一旦完成,我需要清除状态。如果我忘记清除状态,这将是一个不易检测的错误。
  • @YaoDong:坦率地说,在我看来,这根本不像是equals 的工作,如果它是一时的事情就不会。
  • @YaoDong:但这听起来确实像 Facade 模式的工作(我只是不会将它与 equals 一起使用)。我已经更新以提供更多信息。
猜你喜欢
  • 1970-01-01
  • 2016-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多