双向关联,哪个更好?
Bidirectional association, what's better?
问题不大,但是我想过很多次如何在代码中实现双重关联...
让我们举个例子。一个男人车戴一个帽子,一个帽子可以戴在一个男人身上。但如果是男人戴帽子,那帽子的主人就一定是那个男人。
这是我以前的做法 (Java) :
在字符中:
public void setHat (Hat hat) {
Hat former = this.hat;
this.hat = hat;
if (former != null && former.getOwner() == this)
former.setOwner(null);
if (hat != null && hat.getOwner() != this)
hat.setOwner (this);
}
在帽子中:
public void setOwner (Character c) {
Character former = this.owner;
this.owner = c;
if (former != null && former.getHat() == this)
former.setHat(null);
if (c != null && c.getHat() != this)
c.setHat (this);
}
这样一来,男人的帽子和帽子的主人总是很协调。
但是...这对我来说听起来有点笨拙。请问实现这种条件 setter 的更好方法是什么?对我很有用。
(如果我说错了,那只是因为长棍面包好吗?^^)
UP,请^^
一些设计原则适用。 封装 意味着您不会让任何一个对象(帽子或人)处于不一致的状态。我认为您正在通过您的解决方案实现这一目标。
第二个原则称为 Demeter 法则,它的存在是为了通过减少耦合来简化软件维护。它声明一个方法应该只使用
- 其class
的实例字段
- 参数
- 它用
new
构造的对象
目的是让该方法避免要求另一个对象给它一部分内部状态来处理。由于 Hat 有一个 Man 类型的实例字段,反之亦然,它可能还不错。
一个可以应用的设计模式(如果你想去掉冗余代码)可能是 Mediator。这是解决方案的一部分(您实际上可以只使用 class 来处理管理,而不必一直使用中介模式):
这样做的缺点是 Man.setHat
和 Hat.setMan
是 public 方法,任何人都可以在不遵守您可以编程的 "global" 条件的情况下调用你的调解员来做。例如,其他一些 class 可以在几个不同的 Man
对象上调用 setHat(h)
。
在这种情况下,您可以使用断言(按合同设计)来确保调用这些方法的任何人都不会违反所谓的不变量,例如,Man.setHat(h)
的先决条件是 h.man == null OR h.man == this
(它还没有被另一个男人穿)。但是,我不确定这样做是否比您当前的代码 笨拙 少。
最后,您可以在不使用双向关联的情况下应用 KISS 原则。例如,如果 Hat
必须知道它在哪个 Man
上(可能不太可能发生),那么您可以实现一个 Hat.getMan()
方法来遍历已知 Man
列表] 对象,搜索自身(如果您担心凝聚力,则使用其他 class 为您找到它)。性能是您可能不想这样做的原因。
问题不大,但是我想过很多次如何在代码中实现双重关联...
让我们举个例子。一个男人车戴一个帽子,一个帽子可以戴在一个男人身上。但如果是男人戴帽子,那帽子的主人就一定是那个男人。
这是我以前的做法 (Java) :
在字符中:
public void setHat (Hat hat) {
Hat former = this.hat;
this.hat = hat;
if (former != null && former.getOwner() == this)
former.setOwner(null);
if (hat != null && hat.getOwner() != this)
hat.setOwner (this);
}
在帽子中:
public void setOwner (Character c) {
Character former = this.owner;
this.owner = c;
if (former != null && former.getHat() == this)
former.setHat(null);
if (c != null && c.getHat() != this)
c.setHat (this);
}
这样一来,男人的帽子和帽子的主人总是很协调。
但是...这对我来说听起来有点笨拙。请问实现这种条件 setter 的更好方法是什么?对我很有用。
(如果我说错了,那只是因为长棍面包好吗?^^)
UP,请^^
一些设计原则适用。 封装 意味着您不会让任何一个对象(帽子或人)处于不一致的状态。我认为您正在通过您的解决方案实现这一目标。
第二个原则称为 Demeter 法则,它的存在是为了通过减少耦合来简化软件维护。它声明一个方法应该只使用
- 其class 的实例字段
- 参数
- 它用
new
构造的对象
目的是让该方法避免要求另一个对象给它一部分内部状态来处理。由于 Hat 有一个 Man 类型的实例字段,反之亦然,它可能还不错。
一个可以应用的设计模式(如果你想去掉冗余代码)可能是 Mediator。这是解决方案的一部分(您实际上可以只使用 class 来处理管理,而不必一直使用中介模式):
这样做的缺点是 Man.setHat
和 Hat.setMan
是 public 方法,任何人都可以在不遵守您可以编程的 "global" 条件的情况下调用你的调解员来做。例如,其他一些 class 可以在几个不同的 Man
对象上调用 setHat(h)
。
在这种情况下,您可以使用断言(按合同设计)来确保调用这些方法的任何人都不会违反所谓的不变量,例如,Man.setHat(h)
的先决条件是 h.man == null OR h.man == this
(它还没有被另一个男人穿)。但是,我不确定这样做是否比您当前的代码 笨拙 少。
最后,您可以在不使用双向关联的情况下应用 KISS 原则。例如,如果 Hat
必须知道它在哪个 Man
上(可能不太可能发生),那么您可以实现一个 Hat.getMan()
方法来遍历已知 Man
列表] 对象,搜索自身(如果您担心凝聚力,则使用其他 class 为您找到它)。性能是您可能不想这样做的原因。