我是否正确使用了静态?

3

最近我阅读了很多关于使用 static 的文章。我看到了很多有人滥用 static 的情况。我想要确保我在这个 Manager 类中正确地使用了它:

public class SignManager
{
    private static HashMap<String, List<GameSign>> signsBySection   = new HashMap<>();
    private static HashMap<String, List<GameServer>> serversBySection = new HashMap<>();
    private static HashMap<String, GameServer>serverNames = new HashMap<>();
    private static HashMap<Sign, GameSign> gameSignBySign = new HashMap<>();
    private static List<GameServer> availableServers = new ArrayList<>();
    private static List<GameServer> displayedServers = new ArrayList<>();

    public static void addSign(String section, Sign sign)
    {
        List<GameSign> signs = signsBySection.get(section);

        if(signs == null)
            signsBySection.put(section, signs = new ArrayList<>());

        GameSign gameSign = new GameSign(section, sign.getLocation());

        signs.add(gameSign);
        gameSignBySign.put(sign, gameSign);
    }

    public static void addServers(String section, List<String> range)
    {
        List<GameServer> servers = SignManager.serversBySection.get(section);

        if(servers == null)
            SignManager.serversBySection.put(section, servers = new ArrayList<>());

        for(String s : range)
        {
            GameServer server = new GameServer(s);

            servers.add(server);
            serverNames.put(s, server);
        }
    }

    public static void setAvailable(GameServer server)
    {
        availableServers.add(server);
    }

    public static void replaceDisplayed(GameServer old, GameServer newServer)
    {
        removeDisplayed(old);
        displayedServers.add(newServer);
    }

    public static void removeDisplayed(GameServer server)
    {
        displayedServers.remove(server);

        if(server != null)
            server.setSign(null);
    }

    public static boolean isDisplayed(GameServer server)
    {
        return displayedServers.contains(server);
    }

    public static boolean isAvailable(GameServer server)
    {
        return availableServers.contains(server);
    }

    public static void tick()
    {
        for(GameSign sign : getAllGameSigns())
            sign.tick();

        GameSign.addDot();
    }

    public static GameServer getGameServer(String name)
    {
        return serverNames.get(name);
    }

    public static GameServer getNextAvailableServer()
    {
        if(availableServers.size() == 0)
            return null;

        GameServer server = availableServers.get(0);
        availableServers.remove(0);
        return server;
    }

    public static GameSign getGameSign(Sign sign)
    {
        return gameSignBySign.get(sign);
    }

    public static Set<Map.Entry<String, List<GameSign>>> getSignsBySection()
    {
        return signsBySection.entrySet();
    }

    public static Collection<GameServer> getAllServers()
    {
        return serverNames.values();
    }

    public static Collection<GameSign> getAllGameSigns()
    {
        return gameSignBySign.values();
    }
}

我还读到,如果类具有状态,就不应该使用 static。那么使用 static Map 是否意味着这个类具有状态,并且我在这里使用 static 正确吗?
提前感谢。

4
为什么所有的变量和方法都要是静态的?为什么不将它们全部设置为实例变量和实例方法,并确保在需要 SignManager 的地方,您有一个适当的实例?难道有两个具有不同服务器等的不同 SignManager 实例是不可想象的吗?(特别是这样测试会更容易...) - Jon Skeet
3
为什么不只创建一个 SignManager 的实例并使其可供所有需要它的东西使用呢?这将使测试更加容易,以及未来扩展到一个不再一起保存的系统中... - Jon Skeet
你能解释一下为什么静态对于测试不好吗?另外,我确定这个类不会有任何未来的扩展。 - XLordalX
2
a) 你需要在每个测试的开始或结束时做更多的工作来清除全局状态;简单地构造一个新对象会更加干净。 b) 在同一类加载器中无法并行运行你的测试。基本上这是全局状态,更难以理解和处理。至于对未来的确定性 - 我的经验是这很少是一个好主意。 - Jon Skeet
什么是包含Random.java变量的实用类呢?由于Random有状态,所以应该使用单例模式吗? - XLordalX
显示剩余5条评论
2个回答

1
表面上看,我会说你没有正确使用静态。该类维护受addServers和addSign方法影响的状态。该状态被静态地维护,这意味着如果您有两个不同的SignManager对象实例,则两者将共享相同的状态。这可能是您想要的 - 也可能不是。
如果这正是您想要的,则使用单例模式提供了一种更常见的实现方式。如果这不是您想要的,则应考虑将静态变量更改为实例变量(并对方法签名进行相应更改)。

1
如果您在上面的示例中将所有内容设置为 static,那么代码将更加紧密耦合。您可以从此类中删除所有 static 关键字,并在其他组件中使用它的实例,代码仍然正确。
现在,如果您想要创建类的不同实现(或出于某种原因拥有多个实例),则无需更改太多内容,只需将该类的新实现注入到使用它的组件中即可。
对于不使用 static 调用的类编写单元测试也更容易。
这篇文章可能会帮助您更好地了解为什么最好避免使用它们…… http://www.devtrends.co.uk/blog/how-not-to-do-dependency-injection-the-static-or-singleton-container

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接