首页 > 解决方案 > 当创建一个在很多层级都会被频繁引用的java对象时,是使用类实例还是静态类更好呢?

问题描述

我有一个我正在编写的 java 游戏,我需要一个单元原型的主数据库。数据库只是一个包含 HashMap 的类,它存储了几十个包含各个单元类型统计信息的类实例。当游戏生成一个新单位时,它会将该单位从数据库中复制出来,并使用该单位的名称在 HashMap 中定位它。该数据库在程序启动时构建一次,并且不会更改。我也没有扩展或修改存储在 HashMap 中的任何类。它是供游戏系统使用的只读参考。

我还有其他几个班级,基本上是军队,其中包含许多单位。当军队获得一个单位时,它会将单位的信息从数据库中复制出来。我有三种方法可以为军队班级提供读取主数据库的方法。对于创建不会产生奇怪错误的简单易读代码的最佳解决方案,我想请您提出意见。

我已经包含了一些简单的代码来说明不同的方法(很抱歉,如果我错过了分号或其他东西,我很快就把我的例子放在一起,我还在学习 java)。

方法1)我将数据库创建为类实例,每次创建新军队或调用军队方法将单位添加到军队时,我都会将军队或方法的引用作为参数传递给数据库实例。这应该很容易可视化。

方法2)我将数据库创建为类实例。在军队类中,我有一个对数据库实例的静态引用,该引用由军队类中的静态方法设置一次。用数据填充数据库后,调用静态方法并将静态引用设置为指向数据库。此后,军队类将始终能够通过引用静态变量从数据库中提取信息。

class database
{
    // HashMap of unit archetypes
    private HashMap<String, Unit> unitLibrary = new HashMap<String, Unit>();

    // method for storing units in HashMap
    void storeUnits(String fileName)
    {
        // load unit stats from file
        // add new Unit instances to unitLibrary
    }

    // getter method
    Unit getUnit(String unitName)
    {
        return unitLibrary.get(unitName);
    }
}

class Army
{
    // variables
    private static Database masterDatabase;
    private static boolean databaseSet = false;
    ArrayList<Unit> armyUnits = new ArrayList<Unit>();

    // method for creating static database reference
    void setReference(Database d)
    {
        // set static reference to main database if not previously set
        if (!databaseSet)
        {
            masterDatabase = d;
            databaseSet = true;
        }
    }

    // add unit to army
    void addUnit(String unitName)
    {
        armyUnits.add(masterDatabase.getUnit(unitName);
    }   
}

public class CodeTest
{
    public static void main(String[] args)
    {
        // create master database
        Database masterDatabase = new Database();
        masterDatabase.storeUnits("FileOfUnits.game");

        // set static reference in army class to point to master database
        Army.setReference(masterDatabase);

        // Create army
        Army army1 = new Army();
        army1.addUnit("Soldier");
    }
}

方法3)我在数据库类中将HashMap创建为静态的,并使用静态方法来填充数据。数据库类中的 getter 方法也是静态的。现在根本没有传递引用,因为每次军队类实例需要从数据库中提取时,它只是运行 Database.getUnit()。

class database
{
    // HashMap of unit archetypes
    private static HashMap<String, Unit> unitLibrary = new HashMap<String, Unit>();

    // method for storing units in HashMap
    static void storeUnits(String fileName)
    {
        // load unit stats from file
        // add new Unit instances to unitLibrary
    }

    // getter method
    static Unit getUnit(String unitName)
    {
        return unitLibrary.get(unitName);
    }
}

class Army
{
    ArrayList<Unit> armyUnits = new ArrayList<Unit>();

    // add unit to army
    void addUnit(String unitName)
    {
        armyUnits.add(Database.getUnit(unitName);
    }   
}

public class CodeTest
{
    public static void main(String[] args)
    {
        // prepare master database
        Database.storeUnits();

        // create army
        Army army2 = new army2();
        army2.add("Soldier");
    }
}

我已经尝试了所有三种方法,它们都有效,但代码仍处于起步阶段,由于我的早期架构,我不想在路上遇到棘手的错误。我知道它没有以传统的面向对象的方式封装,但方法 3 实际上对我来说似乎是最干净的,因为数据库是在后台创建的,并且从来没有通过一堆不同的方法调用进行访问。该代码的行数也更少,并且没有方法 2 中的技巧。

有这样的建议或经验吗?我用python做了很多,但我最近才开始学习java,还在努力适应封装的限制。

标签: javastatic-methodsencapsulation

解决方案


方法1是最好的。

但是方法 3 实际上对我来说似乎是最干净的,因为数据库是在后台创建的,并且从来没有通过一堆不同的方法调用进行管道访问

对我来说,这似乎是问题的症结所在。您正在尝试使用静态变量解决依赖注入,这是一个糟糕的主意。如果您认为这是一个问题,Spring 之类的框架可以通过诸如自动装配等功能为您省去将对象传递到链中的麻烦。

如果在您的第​​二个示例中,我创建了军队但忘记设置数据库怎么办?我有一个有效地处于半创建状态的对象。对象永远不应该处于这种状态。如果您要求将其传递给构造函数,那么您将避免这个潜在的错误。

您的第二个和第三个示例也存在维护问题,因为当您不知道您的需求可能会如何变化时,它们会将您限制在一个实例中。你怎么知道两个不同的军队总是共享一个数据库?如果将来你想要 aModernUSArmy和 an AncientMacedonianArmy- 你确定它们将共享相同的原型怎么办?


推荐阅读