实现同一类对象之间的双向关系

发布于 2024-11-07 18:38:40 字数 1064 浏览 5 评论 0 原文

我必须实现一个类,其实例彼此之间具有双向关系。例如,我有类 FooBar ,它应该提供方法 sameAs(FooBar x) 并为包含其等效实例的每个实例维护一个 Set 。因此,如果我调用 foo.sameAs(bar)foo 中的 Set 应包含 bar,反之亦然。当然,调用 bar.sameAs(foo) 不起作用。

澄清一下:此类的实例只是语义相等。 equals 仍应返回 false

我提出的解决方案是实现从 sameAs(FooBar x) 调用的私有方法 internalSameAs(FooBar x) 或使用静态方法 <代码>sameAs(FooBar x, FooBar y)。

解决方案 1:

class FooBar {
    Set<FooBar> sameAs = new HashSet<FooBar>();

    public void sameAs(FooBar x) {
        this.internalSameAs(x);
            x.internalSameAs(this);
        }

        public void internalSameAs(FooBar x) {
            sameAs.add(x);
        }
    }

解决方案 2:

class FooBar {
    Set<FooBar> sameAs = new HashSet<FooBar>();

    public static void sameAs(FooBar x, FooBar y) {
        x.sameAs.add(y);
        y.sameAs.add(x);
    }
}

您更喜欢哪一个?为什么?还是有其他我没有想到的方法?

I have to implement a class whose instances have a bidirectional relation to each other. For example I have the class FooBar which should offer the method sameAs(FooBar x) and maintain a Set for each instances containing its equivalent instances. So if I call foo.sameAs(bar), the Set in foo should contain bar and vice versa. Invoking bar.sameAs(foo) doesn't work, of course.

For clarifiction: the instances of this class are only semantically equal. equals should still return false.

The solutions I've come up with is either to implement a private method internalSameAs(FooBar x) which is invoked from sameAs(FooBar x) or to use a static method sameAs(FooBar x, FooBar y).

Solution 1:

class FooBar {
    Set<FooBar> sameAs = new HashSet<FooBar>();

    public void sameAs(FooBar x) {
        this.internalSameAs(x);
            x.internalSameAs(this);
        }

        public void internalSameAs(FooBar x) {
            sameAs.add(x);
        }
    }

Solution 2:

class FooBar {
    Set<FooBar> sameAs = new HashSet<FooBar>();

    public static void sameAs(FooBar x, FooBar y) {
        x.sameAs.add(y);
        y.sameAs.add(x);
    }
}

Which one would you prefer and why? Or is there another way I didn't think about?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

偏闹i 2024-11-14 18:38:40

您使用的命名令人困惑。 sameAs 听起来好像这是一个应该返回布尔值的测试,但从您的代码来看,它似乎更适合命名为 declareSameAs。当您调用 foo.sameAs(bar) 时,您声明 foo 和 bar 相同,而不是进行测试,对吗?

问题是,在您的代码中,您可以声明

x.sameAs(y);
y.sameAs(z);

,但不会出现 x 与 z 相同的情况,这可能不是您想要的(如果是您想要的,您肯定需要更改方法名称)。

在我看来,您希望将实例划分为集合,并让每个实例保留对其所在集合的引用(而不是实例内部的单独集合)。当您做出两个实例相同的新声明时,您需要组合这些集,并确保所有受影响的实例都具有对组合集的引用。

The naming you've used is confusing. sameAs sounds as though it's a test which should return a boolean, but from your code it seems it would be more appropriately named declareSameAs. When you call foo.sameAs(bar), you're declaring that foo and bar are the same, not doing a test, correct?

The problem is that with your code you can declare

x.sameAs(y);
y.sameAs(z);

but it won't be the case that x is the same as z, which is presumably not what you want (and if it is what you want, you definitely need to change the method name).

It seems to me you want to divide your instances into sets, and have each instance keep a reference to the set it's in (not to a separate set internal to the instance). When you make a new declaration that two instances are the same, you need to combine the sets, and ensure all affected instances have a reference to the combined set.

旧梦荧光笔 2024-11-14 18:38:40

您对使用的数据结构是否灵活?如果是这样,您可以使用Multimap(来自Guava Collections),在 FooBar 类的所有实例中都是静态的。在该 Multimap 中,您可以将键作为 FooBar 引用(或唯一的 id,如果有的话),而值将是该 FooBar 的引用(或 id.s)具有 sameAs 关系的 FooBar

are you flexible with the data structures to be used? If so you could use a Multimap (from Guava Collections) that is static amongst all the instances of the class FooBar. In that Multimap you can have the keys as FooBar references (or a unique id if you have one) and the values would be the references (or id.s) of the FooBars that have the sameAs relation.

悲凉≈ 2024-11-14 18:38:40

也许有不同的方式:sameAs 听起来与equals 非常相似。如果我们不需要 equals 来做其他事情,那么我只需在 FooBar 上实现 equals 方法,这样我们就只需执行

 if (foo.equals(bar))
    System.out.println("We're equal (aka: 'equivalent/the same')");

一个在这种情况下,我们不需要任何设置 - 只需要一个规则来确定两个实例是否相等。


您可以将相同信息存储在这些类之外的单独数据结构中。中央地图可以完成这项工作:

 HashMap<FooBar, Set<FooBar>> sameFooBars;

如果您有“相同”的对象,只需将它们添加到地图中即可:

 public static void addSameObjects(FooBar foo1, FooBar foo2) {
   Set<FooBar> set = getMap().get(foo1);
   if (set == null) {
     set = new HashSet<FooBar>();
     getMap().put(foo1, set);
   }
   set.add(foo2);

   // serious implementation avoid code duplication...
   set = getMap().get(foo2);
   if (set == null) {
     set = new HashSet<FooBar>();
     getMap().put(foo2, set);
   }
   set.add(foo1);
}

测试:

public static boolean isSame(FooBar foo1, FooBar foo2) {
  if (getMap().get(foo1) == null) 
    return false;

  return getMap().get(foo1).contains(foo2);
}

Maybe there's a different way: sameAs sounds pretty similiar to equals. If we do not need equals for something else, then I'd simply implement the equals method on FooBar so that we simply do a

 if (foo.equals(bar))
    System.out.println("We're equal (aka: 'equivalent/the same')");

In this case, we do not need any set - just a rule to determine, if two instances are equal.


You could store the sameness information in a separate datastructure outside of those classes. A central map could do the job:

 HashMap<FooBar, Set<FooBar>> sameFooBars;

If you have "same" objects, simply add them to the map:

 public static void addSameObjects(FooBar foo1, FooBar foo2) {
   Set<FooBar> set = getMap().get(foo1);
   if (set == null) {
     set = new HashSet<FooBar>();
     getMap().put(foo1, set);
   }
   set.add(foo2);

   // serious implementation avoid code duplication...
   set = getMap().get(foo2);
   if (set == null) {
     set = new HashSet<FooBar>();
     getMap().put(foo2, set);
   }
   set.add(foo1);
}

And the test:

public static boolean isSame(FooBar foo1, FooBar foo2) {
  if (getMap().get(foo1) == null) 
    return false;

  return getMap().get(foo1).contains(foo2);
}
愁杀 2024-11-14 18:38:40

您真的需要维护所有对象的等价列表吗?如果可能的话,我会将等价集与对象本身分开。这将更容易维护。

然后你可以使用@posdef的多重映射或更简单的Map>与标准 JAVA API 保持一致。

Do you really need to maintain a list of equivalences in ALL objects? If possible I would separate the set of equivalences from the objects themselves. This will be easier to maintain.

Then you can use the multimap of @posdef or more simply a Map> to stay with standard JAVA API.

情绪少女 2024-11-14 18:38:40

您的“双向”samesAs(...) 方法听起来像 Object.equals(...),根据 javadoc 是一个“非等价关系” -空对象引用”。如果这是您想要的,那么您只需在您的类中重写 equals 即可。

当你说“FooBar应该为包含其等效实例的每个实例维护一个集合”时,我有点迷失。如果您想为 FooBar 对象构建等效的类,那么我认为使用 java Collection 来表示它们是个好主意,更准确地说是 Set< /代码>。

这是一个快速破解的示例:

public class FooBar {

    @Override
    public boolean equals(Object other) {
        // do whatever fancy computation to determine if 
        // the object other is equal to this object
    }

}

对于等效的类:

@SuppressWarnings("serial")
public class FooBarEquivalentClass extends HashSet<FooBar> {

    @Override
    public boolean add(FooBar e) {
        if (isEmpty())
            return super.add(e);
        else if (e.equals(iterator().next()))
            return super.add(e);
        else
            return false;
    }

}

Your "bidirectional" samesAs(...) method sounds like Object.equals(...), which, according to javadoc is a "an equivalence relation on non-null object references". If this is what you want, then you just have to override equals in your class.

I'm a bit lost when you say that "FooBar shouldmaintain a Set for each instances containing its equivalent instances". If you want to build equivalent classes for FooBar objects, then I think it's a good idea to use a java Collection to represent them, and more precisely a Set.

Here is a quickly hacked example:

public class FooBar {

    @Override
    public boolean equals(Object other) {
        // do whatever fancy computation to determine if 
        // the object other is equal to this object
    }

}

and for the equivalent class:

@SuppressWarnings("serial")
public class FooBarEquivalentClass extends HashSet<FooBar> {

    @Override
    public boolean add(FooBar e) {
        if (isEmpty())
            return super.add(e);
        else if (e.equals(iterator().next()))
            return super.add(e);
        else
            return false;
    }

}
锦上情书 2024-11-14 18:38:40

“相同”但不“等于”听起来像您应该使用 可比较

我认为实施 compareTo()sameAs() 作为实例方法而不是静态方法,因为您始终需要两个真实实例来进行任何比较。

"same as" but not "equal to" sounds like you should be using Comparable.

I think it makes more sense to implement compareTo() or sameAs() as an instance method rather than a static since you will always need two real instances to do any comparison.

半城柳色半声笛 2024-11-14 18:38:40

听起来您想要的是将等价组与对象实例分开。

制作一个 Map>并注意,当您查找一个对象时,该集合将包含其自身。

Sounds like what you want are to separate the equivalence groups from the object instances.

Make a Map<FooBar, Set<FooBar>> and note that when you lookup an object the set will include itself.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文