java - 面向对象编程——两种方式组合练习?

标签 java oop composition

我的问题涉及面向对象编程中的“组合”方面。我正在用java编程,但这可以适用于任何语言。

我的问题是 2 路组合的问题。我听说组合意味着“有一个”关系。想象一下,您正在构建一个西洋跳棋游戏,在我的例子中,我将有一个“Board”类来生成棋盘,棋盘上有方 block ,方 block 可以有棋子(棋子类),也可以是空的。组合(根据我的理解)会说我们的棋盘中应该有一个方形对象数组,并且方形对象中应该有一个 block 字段。

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)

}

这就是我对组合的理解。我的问题是,是的,棋盘上有方 block 和棋子,但是棋子也有棋盘,这难道没有意义吗?如果您在棋子类中创建了一个移动方法,那么您是否不需要访问棋盘及其方 block ?像这样的事情:

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.)
    }
}

这是否被认为是良好的设计实践,或者是否有更好的方法来实现?

最佳答案

这里确实有两个问题。双向组合——或者一般来说,双向关联——本身并不是问题。这是一种绝对有效的关系类型,尽管在实现中有些不切实际。双向关联又增加了一个依赖关系,而每一个额外的依赖关系都会增加耦合(请查看 Craig Larman 解释的低耦合,作为其 GRASP 原则的一部分)。

不过,有时需要双向关联来反射(reflect)两个对象只有在一起才有意义的事实。是的,你可以说一 block 有一 block 板,但我们在现实生活中真的这么说吗?我们关心这个吗?从域的角度来看,这并不发挥任何关键作用,至少当域只是进行检查时。也许在另一个想象的领域中,我们在许多棋盘之间移动棋子,这种观点可能至关重要,我们可能需要用双向关联对其进行建模。现在,提到域后,我不能避免提到一个经典的 book作者:Eric Evans,关于领域驱动设计。确实,Eric 很好地解释了软件建模领域的所有细微差别。特别是,他还解释了对象之间的双向(双向)关联(第 83 页)。

现在,进入第二期。在您的情况下,需要保留对棋盘的引用并因此保持双向关联,这是由于分配了将棋子移动到错误对象的责任而引起的。移动部件是一种可能影响多个部件的操作,因此一个特定部件无法在不破坏封装的情况下处理该情况。相反,我们应该问,谁是那个能够监督所有棋子并根据领域规则(下棋规则)以适当方式管理它们的负责对象?在不添加任何特殊物体的情况下,在我们已经拥有的物体中,这似乎就是木板。 Board 看起来是一个保存操作 Board 内容的逻辑的好地方(因此我们尊重封装)。

因此,回答您的实际问题,最好将 move() 方法放置到 Board 类中,并自动摆脱不必要的双向关联。作为我提到的有关分配责任的后续内容,我会再次提到 GRASP(它实际上代表一般责任分配原则) - 检查它,我相信它会对这种情况和类似情况有很大帮助。

关于java - 面向对象编程——两种方式组合练习?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55160615/

相关文章:

java - Jython::PythonInterpreter 有哪些模块可用以及如何添加更多

javascript - 模块化/对象化 JQuery

vue.js - 使用 Vue Composition API 获取 API(脚本设置)

java - 在 Java 中使用 synchronized (Thread.currentThread()){...} 的目的是什么?

java - java中如何将字节转换为长整型

Javascript OO引用这个

c++ - 基类构造函数对派生类 C++ 不可见

c# - 您不需要将对象名称传递给构造函数吗? “new Class()”还不是对象

java - 如何确保组合方法的安全?

java - 是什么导致此错误 (java) : "Invalid memory access of location 0x0 rip=0x106282bae"