【问题标题】:Am I abusing static?我在滥用静态吗?
【发布时间】:2015-07-30 04:10:35
【问题描述】:

为了将玩家伪装成另一个实体,我制作了一个伪装类,如下所示:

public class Disguise
{
    private static HashSet<Disguise> disguises = new HashSet<>();
    private net.minecraft.server.v1_8_R2.EntityLiving nmsEntity;
    private Player disguise;

    public Disguise(Player disguise, EntityLiving entity, boolean affectLogin)
    {
        if(affectLogin)
            disguises.add(this);

        this.disguise = disguise;
        this.nmsEntity = entity;
    }

    public Disguise(Player disguise, EntityLiving entity)
    {
        this(disguise, entity, true);
    }

    public void send(Player visible)
    {
        if(visible == disguise)
            return;

        EntityPlayer player = NMSUtils.getNMSPlayer(visible);

        nmsEntity.setPosition(player.locX, player.locY, player.locZ);
        nmsEntity.d(disguise.getEntityId());
        nmsEntity.setCustomName(disguise.getDisplayName());
        nmsEntity.setCustomNameVisible(true);

        PacketPlayOutSpawnEntityLiving spawn = new PacketPlayOutSpawnEntityLiving(nmsEntity);
        PacketPlayOutEntityDestroy destroy = new PacketPlayOutEntityDestroy(disguise.getEntityId());

        player.playerConnection.sendPacket(destroy);
        player.playerConnection.sendPacket(spawn);
    }

    public void send(List<Player> visible)
    {
        for(Player player : visible)
            send(player);
    }

    public void send(Player... visible)
    {
        send(Arrays.asList(visible));
    }

    public void send()
    {
        send(new ArrayList<>(Bukkit.getOnlinePlayers()));
    }

    public Player getDisguised()
    {
        return disguise;
    }

    public static HashSet<Disguise> getDisguises()
    {
        return disguises;
    }
}

我还有一个静态 HashSet,它存储所有创建的实例。我这样做是因为我希望登录的玩家也能看到伪装,并且我想在玩家退出时从玩家身上移除伪装。是静态 HashSet 的方法吗(就像我正在做的那样)?如果没有,应该怎么做?

【问题讨论】:

  • 首先,我会封装return disguises;,否则其他类可以开始变异HashSet&lt;T&gt;,永远不要返回原始集合本身......
  • 你在滥用静态,如果你试图做 OOP 而是通过永远不必创建新对象而使其成为引用编程,而只需要调用类而无需创建实例。
  • 你认为 HashSet 是静态的有什么问题?我不确定我看到了。他有一个集中的存储库,不需要实例。难道是因为他把它藏在了伪装之中?我只会有它的访问器/突变器....永远不要直接公开一个集合。
  • @jgr208 我不确定我是否明白你在说什么,但据我了解,我应该删除构造函数和 HashSet 并使发送静态?
  • 那么您的程序是否需要或者您是否希望它是 OOP,如果是,则不要使用静态,除非您不需要像实用程序类这样的类的实例。如果您不关心 OOP 并在需要为类使用函数时创建类的新实例,请继续并在任何地方使用静态。一切都取决于您想要做什么的设计。

标签: java bukkit


【解决方案1】:

static 要求它。就其性质而言,它很容易被“滥用”,但这只是挑战的一部分。

说到底,如果你的模组做了你需要它做的事情而没有错误,不要过分强调这个粒度级别的最佳实践(一个特定的变量)。它不可能扩大到糟糕的设计会给您带来问题的程度。毕竟,这不是一个生命支持系统。

如果你想为了好玩而练习良好的形式,我的第一反应是把你的管理逻辑从 Disguise 转移到一个(例如)DisguiseManager 类,并通过一个管理器类处理所有 Disguise 创建/销毁。不太复杂的是伪装上的私有构造函数和静态创建/销毁方法。像您发布的构造函数中的全局副作用通常是不好的形式。

【讨论】:

  • 那么我是否必须将 Singleton 用于 Manager 类,因为我只想拥有一个伪装列表。
  • 我不明白为什么你“必须”做任何事情。 Singleton 本质上是一个穿着漂亮衣服的静态全局变量。如果你只想要一个列表,那么只实例化一个。没必要想太多:)
【解决方案2】:

基本上每次调用构造函数时,您都希望将this 添加到全局位置。

没关系,但有两个问题:

  1. 在构造函数中暴露this 是危险的,需要仔细分析。 (你的代码在这方面有问题)
  2. 并发 - 如果应用程序是多线程的,它需要是线程安全的。 (在构造函数中暴露this 在并发环境中问题更大)
  3. 垃圾收集 - 当对象变成“垃圾”时,如何将其从全局位置移除。

【讨论】:

  • 持有伪装的玩家退出时,该对象从HashSet中移除。
【解决方案3】:

当您的代码变大时,使用静态对象会变得非常令人沮丧,并且该对象有很多访问器。如果您要调试代码,您将如何捕获操作 HashSet 的确切代码?

您为什么不使用 HashSet 重构客户端,以通过 getter 获取它?将 HashSet 实例封装为 Singleton 怎么样?听起来好像只创建了一个 HashSet 来存储玩家/伪装。

使用任何类型的 getter 方法,比如通过 Singleton,您可以轻松地在访问 HashSet 之前或之后添加额外的代码。例如,在每次使用返回 HashSet 的方法后,您可以打印 HashSet 的内容。您也可以使用静态对象来做到这一点,但是找到静态对象的所有用法的噩梦......

【讨论】:

  • 不会使用单例导致同一点吗?因为我确信未来不会有任何实现。
  • @XLordalX 更新了我的答案,突出显示有什么不同。
  • 请不要使用单例,关于这可能导致的问题有详细记录 -> stackoverflow.com/questions/12755539/…
  • @MrWiggles 从您的链接中接受的答案指出“如果您发现要使用单例,您可能需要考虑您的设计,但有时它很有用。"
  • 这种情况极为罕见,事实上我认为在设计良好的系统中根本不会
猜你喜欢
  • 2016-07-03
  • 2011-05-07
  • 2018-04-26
  • 2018-06-14
  • 1970-01-01
  • 2014-10-30
  • 2011-05-31
  • 1970-01-01
  • 2015-03-29
相关资源
最近更新 更多