有一个空方法可以吗?

Is it OK to have an empty method?

是否可以拥有一个空方法并在其子class(es) 中覆盖它? 这就是我的代码中的样子。

public class Rook() {

    public void voidCastleRight() { }

}

public class ShortRook() extends Rook {

    @Override
    public void voidCastleRight() {
        getPlayer().setkSC(false); //void King Side Castling (Short Castle)
    }

}

public class LongRook() extends Rook {

    @Override
    public void voidCastleRight() {
        getPlayer().setqSC(false); //void Queen Side Castling (Long Castle)
    }
}

上下文是国际象棋引擎。它写在 Java 中,它必须搜索下一个 'best' 移动才能使棋盘处于给定状态。因此,尽可能高效地实现所有内容非常重要,因为许多方法将被调用数百万次。因此,我想要这种 Rook 的层次结构,而不是一个 Rook class,在后者中我必须检查 Rook 在哪一侧,并检查 Rook 是否在其初始位置等。

第一次创建Board时,会有一个ShortRook和一个LongRook。随着游戏的进行,可能会因为 Pawn 的提升而将更多的 Rooks 引入游戏中。这些将是 Rook 的实例化。

只要移动 Rook,就会调用方法 voidCastleRight()。由于 Pawn 升级而存在的 Rooks 不应在移动时使城堡无效(空方法)。自游戏开始以来就存在的车,在移动时应该使城堡权利无效(子classes 中的方法)。

我还编写了一个解析器,它接受 FENStrings 并将它们转换为 Board,反之亦然。当 Rooks 不在初始位置时,无法判断哪个是 Short-Rook 和 LongRook。这不是问题,因为城堡权利已经作废,它们可以解析为 Rook 的实例。因此,如果我将一个 Short- 或 LongRook 对象投射到 Rook,只要它使相关的城堡权利无效(即它已经移动),就可以了吗?这样它就不会在城堡已经作废时不必要地作废它。我不关心这些解析器方法的复杂性,因为它们不会用于搜索。

虽然有些人可能认为这些想法是微优化 "which are the root of all evil",但当方法必须被调用几百万次时,这些优化可能会得到回报。我也更关心 OOP 范例。

PS:我知道 Java 不是用于此应用程序的最佳语言,它无关紧要。我知道对象创建(在 Java 中)很昂贵。我会确保在搜索过程中没有创建任何对象。

虽然有一个什么都不做的空方法当然没问题,但您应该评估它的替代方案 - 一个完全缺失的空方法,即 abstract 方法。

这可能适用于您的情况,因为您将创建 ShortRookLongRook 或提升的 Rook:

public abstract class AbstractRook() {
    public abstract void voidCastleRight();
}

public class ShortRook() extends AbstractRook{
    @Override
    public void voidCastleRight() {
        getPlayer().setkSC(false); //void King Side Castling (Short Castle)
    }
}

public class LongRook() extends AbstractRook{
    @Override
    public void voidCastleRight() {
        getPlayer().setqSC(false); //void Queen Side Castling (Long Castle)
    }
}

public class PromotedRook() extends AbstractRook{
    @Override
    public void voidCastleRight() {
        throw new IllegalStateException("Promoted rook cannot castle");
    }
}

您问题标题的答案:

Is it OK to have an empty method?

是响亮的 是的 - 这是完全可以接受的情况。

但是 - 我觉得您使用的工具不符合您的要求。我不认为禁用 castling 的功能应该是 Rooks 功能的一部分。你需要的是一个 watcher/listener 来监视车的移动并在正确的情况下禁用易位。然后,您可以为 enabling/disabling 使用类似的架构,以 En-Passant 为例。

还请记住 Castling 只有当 国王从未移动过 时才能进行易位,所涉及的 车从未移动过移动国王和涉及的车之间的方格未被占用国王未被检查king 不会越过或结束在它会被检查的方格上。您可以使用 rooks、kings 和 move engine 上的侦听器在一个地方实现整个规则。

我会考虑一个什么都不做的非抽象方法 code smell

这里的第一个替代方法是创建一个 Rook 接口而不是 class。

如果你想给你的基础class具体功能,你会考虑第二种选择,也许定义你引用的getPlayer()方法,然后使用抽象class和将方法标记为抽象。

与您的问题无关,但我会考虑您代码的其他两个方面。首先是在您的方法中使用名称 "void",这有点尴尬。

最后,我通常会告诉人们重新考虑使用 void 函数。原因是 void 函数,根据定义,什么都不做或执行 side effect。副作用本身并不坏,但由于它涉及修改状态,它会使你的程序更难推理。

例如,考虑一种方法 validMoves(),即 returns 棋子可以做出的有效移动列表。在这种情况下,您可以只拥有一个 Piece 界面,并在评估可能的移动时对每一块都一视同仁:

interface Piece {
    List<Move> validMoves();
}

在这种情况下,您将只有一个 Rook 实例 class;一个在国王的两边。您不必为 Kings、Rooks 和 Pawns 定义特殊方法,因为他们每个人都知道他们可以采取的行动。

这会大大扁平化您的 class 层次结构,并使处理和评估电路板更容易推理。