6

我只是想知道我所做的是否是某种糟糕的设计。

我有一个 ArrayList 的东西。我需要这个列表永远存在。我只需要这些列表之一。我也有一些方法可以与这个列表进行交互。因此,我将所有内容都设为静态。

问题是,由于所有这些东西都隐藏在一个类中,因此该类中的所有内容都被声明为静态的。这似乎有点奇怪,因为这就像我想让整个班级都是静态的。

Java 不允许我将整个类设为静态以及我被教导在代码中最小化静态方法的事实在我的脑海中敲响了一些警钟,但老实说,我看不出任何合理的理由为什么我做的不会很好。

编辑:更多关于该程序以及为什么我决定做我所做的事情,因为我想这会有所帮助(当然有人问过)。

程序的中心是两个数据库,一个用于项目,另一个用于字符。角色需要临时拥有物品,但所有物品都必须能够随时列出。

我决定我将有一个项目数组列表,每个项目都有一个布尔值标记它可用或不可用(便于显示所有项目和可用项目)。每个字符都有自己的、较小的项目数组列表,我将从数据库中添加项目的副本。

为了能够从其他类访问数据库(这是我开始这个想法的地方),我考虑了我最简单的选择,即简单地将大型数组列表设为静态,因为没有任何情况我需要它不存在并且没有任何情况我需要不止一个。当然,当我将列表设为静态时,我还需要将与之交互的所有基本方法设为静态。

我很确定有更好的方法来做我想做的事情,但我只是一个初学者练习。

EDIT2:哦,项目列表将被添加到,从中删除,并且在程序运行时修改了项目。角色收到物品副本的另一个效果是,只要他们拥有物品,他们自己的物品就会保持不变。

4

4 回答 4

4

如果您 Thing的系统中只需要一个 s 列表,您需要问自己这些东西是什么。它们是可以在每次运行之前配置的项目吗?它们会随着用户执行程序而改变吗?也许这些东西应该作为记录存储在数据库中,甚至是轻量级的内存数据库,如 Apache Derby 或 NoSQL 数据库。

即使您确实拥有一组固定的项目,您也应该考虑使用依赖注入系统并在单例范围内出售列表,而不是使用硬连线的单例。这样,您可以通过更改配置来替换测试类中的列表。

如果您发现最后一个令人困惑,请考虑这个。假设您有一个处理 的类Things,例如在其中保留它们的静态列表。就像是:

public class ThingCatalog {
    private static final List<Thing> things = new ArrayList<>();
    public ThingCatalog() {
        // initialize list of things.
    }
    public List<Thing> getThings() {
        return things;
    }
    public Thing getThingWithId(int id) {
        // ...
    }
}

现在,您可以创建ThingCatalog一个单例类;你已经看到了怎么做。将构造函数设为私有,并创建一个静态getInstance方法。你会很想写

public class TreasureGenerator {
    private ThingCatalog things = ThingCatalog.getInstance();
    // ...
}

如果你想为这个类中不使用东西的方法编写单元测试会发生什么?你不需要这些东西,所以你根本不需要 ThingCatalog。不幸的是,你被它困住了。

你可以通过给 TreasureGenerator 一个 setThingCatalog 方法来解决这个问题:

public void setThingCatalog(ThingCatalog things) {
   this.things = things;
}

当然,您只有一个 ThingCatalog,所以这并没有多大帮助。但是如果你有一个 ThingCatalog 可以实现的接口:

public interface ThingVendor {
    List<Thing> getThings();
    Thing getThingById(int id);
}

并且您所有的类都使用 ThingVendor 而不是 ThingCatalog,您可以在测试中替换它。

这是一个更像商业的例子。你正在编写一个财务程序,你需要让它在支票上打印今天的日期。典型的是编写如下代码:

String recipient = ...;
String accountOwner = ...;
BigDecimal amount = ...;
String accountNumber = ...;
Date today = new Date();
printCheck(...);

现在,有人问你“你的程序能正确处理闰日吗?” 十四年前,问题可能与千年虫有关。你将如何测试这个?你今天被这个方法困住了。

相反,您编写了一个名为的接口DateGenerator

public interface DateGenerator {
    Date today();
}

public class TodayGenerator implements DateGenerator {
    public Date today() { return new Date(); }
}

public class LeapDayGenerator implements DateGenerator {
    public Date today() {
        Calendar cal = Calendar.getInstance();
        cal.set(2016, FEBRUARY, 29); // assume static imports;
        return cal.getTime();
    }
}

您的类将有一个 setDateGenerator 方法,并且您将正常使用 TodayGenerator。在您的闰日测试中,您将使用 LeapDayGenerator。

依赖注入系统使这些过程自动化。如果您继续从事计算,您将从经验中学到的是对象不应该知道如何配置自己。项目的其他部分应该将对象粘合在一起。

于 2013-05-20T02:44:50.717 回答
2

很抱歉,但我担心您的计划可能是一个糟糕的计划,并且您可能需要重新设计您的程序。你的班级有一个状态,这向我表明它不应该是静态的。

应该是静态的东西:

  • 常数
  • 实用方法
  • 属于类而不是实例的字段。

考虑向我们提供有关您的程序结构的更多信息,以便我们给出更准确的答案。

于 2013-05-20T02:38:03.187 回答
2

根据您的更新,您已经达到了经典的“这是一个单身人士!” 片刻之后,有人应该向您指出“它(几乎)从来不是单身!”。相反,这应该是一个普通的、非静态的、非单例的类,并且应用程序的其余部分应该被编写为始终使用它的单个实例。您的应用程序只需要一个事物的单个实例这一事实并不会使该事物成为单例。阅读从 Google 搜索“why is singleton evil”“singleton antipattern”中出现的几篇文章,您会受益匪浅。

听起来您可能在谈论共享的可变状态,这是一个完整的(巨大的)蠕虫罐,如果没有仔细考虑,您就不想进入。

于 2013-05-20T03:04:38.230 回答
1

我倾向于同意您的设计听起来并不理想。您的许多目标似乎是典型的过程性而非面向对象编程的目标。

如果你发现你的项目对静态可变数据有很强的依赖,那么你应该问问自己为什么需要这么多全局数据。

于 2013-05-20T04:11:01.563 回答