实现同一类对象之间的双向关系
我必须实现一个类,其实例彼此之间具有双向关系。例如,我有类 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);
}
}
您更喜欢哪一个?为什么?还是有其他我没有想到的方法?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
您使用的命名令人困惑。
sameAs
听起来好像这是一个应该返回布尔值的测试,但从您的代码来看,它似乎更适合命名为declareSameAs
。当您调用 foo.sameAs(bar) 时,您声明 foo 和 bar 相同,而不是进行测试,对吗?问题是,在您的代码中,您可以声明
,但不会出现 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 nameddeclareSameAs
. When you callfoo.sameAs(bar)
, you're declaring thatfoo
andbar
are the same, not doing a test, correct?The problem is that with your code you can declare
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.
您对使用的数据结构是否灵活?如果是这样,您可以使用
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 classFooBar
. In thatMultimap
you can have the keys asFooBar
references (or a unique id if you have one) and the values would be the references (or id.s) of theFooBar
s that have thesameAs
relation.也许有不同的方式:
sameAs
听起来与equals
非常相似。如果我们不需要equals
来做其他事情,那么我只需在FooBar
上实现equals
方法,这样我们就只需执行一个在这种情况下,我们不需要任何设置 - 只需要一个规则来确定两个实例是否相等。
您可以将相同信息存储在这些类之外的单独数据结构中。中央地图可以完成这项工作:
如果您有“相同”的对象,只需将它们添加到地图中即可:
测试:
Maybe there's a different way:
sameAs
sounds pretty similiar toequals
. If we do not needequals
for something else, then I'd simply implement theequals
method onFooBar
so that we simply do aIn 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:
If you have "same" objects, simply add them to the map:
And the test:
您真的需要维护所有对象的等价列表吗?如果可能的话,我会将等价集与对象本身分开。这将更容易维护。
然后你可以使用@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.
您的“双向”
samesAs(...)
方法听起来像Object.equals(...)
,根据 javadoc 是一个“非等价关系” -空对象引用”。如果这是您想要的,那么您只需在您的类中重写equals
即可。当你说“
FooBar
应该为包含其等效实例的每个实例维护一个集合”时,我有点迷失。如果您想为FooBar
对象构建等效的类,那么我认为使用 javaCollection
来表示它们是个好主意,更准确地说是Set< /代码>。
这是一个快速破解的示例:
对于等效的类:
Your "bidirectional"
samesAs(...)
method sounds likeObject.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 overrideequals
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 forFooBar
objects, then I think it's a good idea to use a javaCollection
to represent them, and more precisely aSet
.Here is a quickly hacked example:
and for the equivalent class:
“相同”但不“等于”听起来像您应该使用
可比较
。我认为实施
compareTo()
或sameAs()
作为实例方法而不是静态方法,因为您始终需要两个真实实例来进行任何比较。"same as" but not "equal to" sounds like you should be using
Comparable
.I think it makes more sense to implement
compareTo()
orsameAs()
as an instance method rather than a static since you will always need two real instances to do any comparison.听起来您想要的是将等价组与对象实例分开。
制作一个 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.