我的问题与面向对象编程中的“组合”方面有关。我正在用Java编程,但这可能适用于任何语言。
我的问题是2向合成。我听说构图意味着“有”关系。假设您正在构建一个跳棋游戏,就我而言,我将拥有一个用于生成棋盘的“棋盘”类,一个棋盘具有正方形,并且正方形可以具有棋子(棋子类),也可以是空的。组合(根据我的理解)会说我们的木板中应该有一个正方形的对象阵列,而正方形中的一个对象应该是一块区域。
public class Board {
private List<Square>;
... (generating board, other functions/fields)
}
public class Square {
private Piece piece;
... (other functions/fields)
}
public class Piece {
... (functions/fields)
}
这就是我对构图的理解。我的问题是,是的,一块木板有正方形和一块,但是一块也有一块木板,这不是很有意义吗?如果您在piece类中创建了move方法,您是否不需要访问木板及其正方形?像这样:
public class Piece {
private Board board;
... (constructor/functions/fields)
public void move(int x, int y) {
if (this.board.getSquare(x, y).isEmpty())
System.out.println("Piece moves to (x, y)");
... (etc.)
}
}
这被认为是好的设计实践,还是有更好的方法来实现呢?
答案 0 :(得分:2)
circular dependency导致紧密耦合。通常认为这是不良做法。紧密耦合的组件相互依赖。当您打算更改Board类时,您可能也需要更改Piece类。而且,如果系统不断壮大,这项任务将变得越来越困难。
尝试从组件的责任方面考虑。自己移动并控制电路板是这块的责任吗?董事会可以做的更好吗?
public class Board {
public void move(Piece piece, int x, int y) {
}
}
答案 1 :(得分:2)
这里确实有两个问题。双向组合-或通常来说是双向关联-本身不是问题。这是一种绝对有效的关系类型,尽管在实现中有些不切实际。双向关联增加了一个依赖关系,每增加一个依赖关系都会增加耦合(请查看Craig Larman解释为“低耦合”,作为其GRASP原理的一部分)。
仍然,双向关联有时是必要的,以反映两个对象仅在一起才有意义的事实。是的,您可以说一块有一块木板,但是在现实生活中我们真的这么说吗?我们在乎吗?从域的角度来看,这并没有扮演任何至关重要的角色,至少在域只是在扮演支票的时候。也许在另一个虚构的领域中,即我们在许多板之间移动零件时,这种观点可能至关重要,因此我们可能需要使用双向关联对其进行建模。现在,已经提到了域,我不禁要提到Eric Evans关于域驱动设计的经典book。确实,Eric很好地解释了使用软件建模领域的所有细微差别。特别是,他还解释了对象之间的双向关联(第83页)。
现在,进入第二期。在您的情况下,有必要保留对董事会的参考,从而保持双向联系,这是由于分配职责将棋子移到错误的对象上引起的。移动部件是一项可能影响多个部件的操作,因此,一个特定部件无法处理而不会破坏封装。相反,我们应该问,可以负责监督所有事务并根据域规则(打支票规则)以适当方式对其进行管理的负责任的对象是谁?在没有添加任何特殊对象的情况下,似乎已经是董事会了。电路板看起来很不错,可以容纳操纵电路板内容的逻辑(因此我们尊重封装)。
因此,回答您的实际问题,最好将move()方法放置到Board类中,并自动摆脱不必要的双向关联。作为我提到的有关职责分配的后续活动,我会再次提及GRASP(它实际上代表一般职责分配原则)-对其进行检查,我相信在这种情况和类似情况下,它将大有帮助。