有一个空方法可以吗?
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 方法。
这可能适用于您的情况,因为您将创建 ShortRook
、LongRook
或提升的 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 的功能应该是 Rook
s 功能的一部分。你需要的是一个 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 层次结构,并使处理和评估电路板更容易推理。
是否可以拥有一个空方法并在其子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 方法。
这可能适用于您的情况,因为您将创建 ShortRook
、LongRook
或提升的 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 的功能应该是 Rook
s 功能的一部分。你需要的是一个 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 层次结构,并使处理和评估电路板更容易推理。