如何简化这段 Java 代码?

How to simplify this Java code?

我正在为名为 Spigot (spigotmc.org) 的 Minecraft 服务器软件编写一些 Java 代码,我刚刚编写了这个。目标是检查变量 block 的每一侧并检查墙上的标志,如您所见。它应该只需要找到一个。然后它会更新它等等。我知道这段代码可以简化,但目前我看不出如果不为条件语句中的代码创建一个全新的函数,我不想这样做。有没有更好的方法来写这个条件?

// Get an attached sign
Block sign;
if ((sign = block.getRelative(BlockFace.NORTH)).getType() == Material.WALL_SIGN) {
    org.bukkit.block.Sign data = (Sign) sign.getState();
    data.setLine(1, "OFF");
    data.update();
} else if ((sign = block.getRelative(BlockFace.EAST)).getType() == Material.WALL_SIGN) {
    org.bukkit.block.Sign data = (Sign) sign.getState();
    data.setLine(1, "OFF");
    data.update();
} else if ((sign = block.getRelative(BlockFace.WEST)).getType() == Material.WALL_SIGN) {
    org.bukkit.block.Sign data = (Sign) sign.getState();
    data.setLine(1, "OFF");
    data.update();
} else if ((sign = block.getRelative(BlockFace.SOUTH)).getType() == Material.WALL_SIGN) {
    org.bukkit.block.Sign data = (Sign) sign.getState();
    data.setLine(1, "OFF");
    data.update();
}

您的内部 if 范围始终相同,因此您可以在条件之间使用 "or" 命令:

// Get an attached sign
Block sign;
if (((sign = block.getRelative(BlockFace.NORTH)).getType() == Material.WALL_SIGN) 
 || ((sign = block.getRelative(BlockFace.EAST)).getType()  == Material.WALL_SIGN)
 || ((sign = block.getRelative(BlockFace.WEST)).getType()  == Material.WALL_SIGN)
 || ((sign = block.getRelative(BlockFace.SOUTH)).getType() == Material.WALL_SIGN)
    org.bukkit.block.Sign data = (Sign) sign.getState();
    data.setLine(1, "OFF");
    data.update();
}

可能是循环?

// Get an attached sign
Block sign;
BlockFace[] faces = new BlockFace[] {
    BlockFace.NORTH,
    BlockFace.EAST,
    BlockFace.WEST,
    BlockFace.SOUTH};

for(BlockFace face : faces) {
    if ((sign = block.getRelative(face)).getType() == Material.WALL_SIGN) {
        org.bukkit.block.Sign data = (Sign) sign.getState();
        data.setLine(1, "OFF");
        data.update();
        break;
    }
}

当您有很多选择要查看时,这种方法很有效。另外,如果你在其他地方做类似的逻辑,一定要创建一个所有有相同需求的客户都可以调用的函数!

根据DRY原则,您需要重复使用重复的部分。在您的示例中,整个 if 块是相同的,除了面部。

  1. 将 ifs 替换为 for:

    List<BlockFace> blockFaces = Arrays.asList(BlockFace.NORTH, BlockFace.EAST, BlockFace.WEST, BlockFace.SOUTH);
    for (BlockFace face : blockFaces) {
        Sign sign = block.getRelative(face);
        if (sign.getType() == Material.WALL_SIGN) {
            org.bukkit.block.Sign data = (Sign) sign.getState();
            data.setLine(1, "OFF");
            data.update();
            break;
        }
    }
    
  2. 提取方法:

    private boolean updateAttachedSign(Block block, BlockFace face) {
        Sign sign = block.getRelative(face);
        if (sign.getType() == Material.WALL_SIGN) {
            org.bukkit.block.Sign data = (Sign) sign.getState();
            data.setLine(1, "OFF");
            data.update();
            return true;
        }
        return false;
    }
    
    {
        boolean signIsUpdated =
            updateAttachedSign(block, BlockFace.NORTH) ||
            updateAttachedSign(block, BlockFace.EAST) ||
            updateAttachedSign(block, BlockFace.WEST) ||
            updateAttachedSign(block, BlockFace.SOUTH);
    }
    

第二种解决方案,尽管总体上是更好的方法,但对于您的情况来说似乎有点过于复杂。我会坚持第一个。

@Constantin编辑:

谨慎使用短路条件。请参考这篇优秀的 post 了解其中的意义 https://softwareengineering.stackexchange.com/questions/284415/short-circuit-evaluation-is-it-bad-practice