德尔福单位没有“从根本上坏掉”。它们的工作方式促进了编译器的惊人速度并促进了干净的类设计。
能够以 Prims/.NET 允许的方式将类分布在单元上,这种方法可以说从根本上被破坏了,因为它允许开发人员忽略正确设计其框架的需要,从而促进了类的混乱组织,从而促进了任意代码结构规则,例如“每个单元一个类”,作为通用格言没有技术或组织价值。
在这种情况下,我立即注意到由于这种循环引用困境而导致的类设计中的一种特殊性。
也就是说,为什么一件作品需要参考一块木板?
如果一块棋子是从棋盘上取下来的,那么这样的引用就没有意义了,或者被移除的棋子的有效“移动目标”可能只是那些对该棋子有效的作为新游戏中的“起始位置”的那些?但我认为这对于一个要求 GetMoveTargets 支持使用 NIL 板引用的调用的案例来说,除了任意理由之外没有任何意义。
在任何给定时间单个棋子的特定位置是单个国际象棋游戏的属性,同样,任何给定棋子可能的有效移动取决于游戏中其他棋子的位置。
TChessPiece.GetMoveTargets不需要当前游戏状态的知识。这是TChessGame的职责。并且TChessPiece不需要参考游戏或棋盘来确定给定当前位置的有效移动目标。棋盘约束(8 个等级和文件)是域常量,而不是给定棋盘实例的属性。
因此,需要一个TChessGame来封装包含对棋盘、棋子和 - 至关重要的是 - 规则的认识的知识,但棋盘和棋子不需要相互了解或了解游戏。
将与不同片段有关的规则放在片段类型本身的类中似乎很诱人,但这是一个错误恕我直言,因为许多规则是基于与其他片段的交互,在某些情况下与特定片段类型的交互。这种“大局”行为需要对整个游戏状态有一定程度的监督(阅读:概述),这在特定的棋子类别中是不合适的。
例如,如果这些对角格中的任何一个被占用,则 TChessPawn 可以确定有效的移动目标是向前一格或两格,或者向前对角格一格。但是,如果棋子的移动使国王处于 CHECK 状态,则棋子根本无法移动。
我会通过简单地允许 pawn 类指示所有可能的移动目标来解决这个问题 - 向前 1 或 2 个方格和两个对角线前方方格。TChessGame然后通过参考这些移动目标的占用率和游戏状态来确定其中哪些是有效的。仅当兵在其本垒上时,才可能向前走 2 个方格,向前方格被占用阻止移动 = 无效目标,未占用的对角线方格促进移动,如果任何其他有效的移动暴露了国王,那么该移动也是无效的。
再一次,诱惑可能是将普遍适用的规则放在基础TChessPiece类中(例如,给定的移动是否暴露了国王?),但应用该规则需要了解整体游戏状态 - 即其他棋子的放置 - 所以它更多正确地属于TChessGame类的一般行为,恕我直言
除了移动目标之外,棋子还需要指明 CaptureTargets,这在大多数棋子的情况下是相同的,但在某些情况下却完全不同 - pawn 就是一个很好的例子。但同样,所有潜在捕获中的任何一个 - 如果有的话 - 对于任何给定的动作都是有效的 - 恕我直言 - 对游戏规则的评估,而不是一块或一类棋子的行为。
与 99% 的此类情况(ime - ymmv)一样,通过更改类设计以更好地表示正在建模的问题,而不是找到将类设计硬塞到任意文件组织中的方法,或许可以更好地解决困境。