假设我有理由要求通过多个值类型快速查找类实例,为了便于说明,我将使用游戏服务器作为示例。
假设服务器使用静态标识号处理用户。此号码用于与特定玩家进行交流和互动(即:私有(private)聊天、交易请求、战斗、公会邀请等)。
这需要经常使用通过他们的身份证号查找玩家,根据我目前的经验,最好的方法是这样的:(如果我错了请纠正我。)
HashMap<Integer, Player>
然而,在处理网络时,很多时候我还需要让播放器与网络 session 相关联,或者某些人可能更熟悉的“套接字”。看起来像这样:
HashMap<Connection, Player>
所以我想弄清楚的是,我应该走这条路吗:
HashMap<Integer, Player> playersById;
HashMap<Connection, Player> playersByConnection;
或者我应该像这样做一些更“粉碎”的事情:
HashMap<Object[], Player> playersOnline;
并且有Object[0]
作为整数,Object[1]
作为连接,然后使用查找期间所需的连接。
或者这两种方法都是低效和不正确的,是否有更好/更快的方法来通过 Integer 或 Connection 查找它们而不复制集合?
任何见解将不胜感激。
编辑:此外,有什么反对 HashSet<>
的吗?和一个 HashMap<>
包含相同的类引用?我注意到 HashSet<>
比 HashMap<>
的迭代效率高得多并一直保留一个 Map 用于查找和一个 Set 用于迭代,这是不好的做法吗?
我当然会建议您为两个不同的搜索使用单独的 map 。它们确实是完全不同且独立的需求。您以后可能还需要添加新的方式来查找玩家(按名称、位置或游戏实例)。您不希望必须返回并继续更改现有的工作数据结构。
我的建议是将您的两个搜索 map 都封装在包含玩家或联系人列表的类中。这样一来,它们就成为这些类中的内部实现细节,而不是 Player
类(例如)需要担心的事情。
所以,例如:
class PlayerPopulation {
private final List<Player> playerList = new ArrayList<>();
private final Map<Player.ID, Player> playerByID = new HashMap<>();
public void addPlayer(Player player) {
playerList.add(player);
playerByID.put(player.getID(), player);
}
public Player getPlayerByID(Player.ID id) {
return playerByID.get(id);
}
}
相同的模式将用于 ConnectionPool
(或您的连接容器的任何名称)。这样你就可以轻松地添加新的搜索玩家的方式,而无需任何其他类担心你正在使用的 map 结构。您还可以简单地转换为 HashSet
或其他任何东西,而不会在一个类之外受到任何影响。如果您试图使 map 支持多个搜索路径,则不能这样做。
我还将 ID
更改为内部类,而不是假定 Integer
。我意识到您只是在举一个例子,但认为这是良好封装的另一个例子:您可以更改为 Long
而根本不更改 PlayerPopulation
类。
所以是的,我绝对建议不要将搜索键混合在一起。