java - 这是对单例的适当使用吗?

标签 java performance design-patterns configuration singleton

我最近一直在阅读,单例模式经常是一种被滥用的设计模式。我知道全局变量 可能 不好并且单例不可扩展(因此不是好的 OO 设计),但我想知道在这种情况下我是否“正确”使用了它。

本质上,我有一些软件在自动售货机上运行。它有一个管理员控制台,您可以在其中登录和配置一些东西。例如,今天我想要一个 3 美元的可乐瓶和一个 2 美元的雪碧,所以我只需登录到这个管理控制台并编辑这些值。然后,在我的代码中,我可以使用一些 Java 代码从控制台读取这些配置参数:

AdminConsole adminConsole = new AdminConsole();
Map<String, Int> drinkPriceMap = adminConsole.getSettings();

这会加载一个键值对映射,例如 Coke:3、Sprite:2、Water:2 和 将在“主”类首次在机器启动时实例化时发生。

饮料的价格只应在每次硬件重置时更新。

现在,由于这台自动售货机的硬件非常有限,而且从控制台中提取设置对它来说非常占用内存,所以我想在做事时考虑到这一点。

当 AdminConsole 被实例化时,它会从管理控制台中提取这些值并生成映射。提取这些值的行为是一项占用大量内存的操作,而映射并不是什么大问题。因此,我想在代码中做的是使 AdminConsole 成为一个单例,因此它只能被实例化一次。这样一来,当新开发人员加入团队并且没有意识到这是内存有限的硬件上的内存消耗大的操作时,他不会意外地多次实例化它。

相反,它看起来像这样:

AdminConsole adminConsole = AdminConsole.getInstance();
Map<String, Int> drinkPriceMap = adminConsole.getSettings();

那么,您认为我在这里以良好的方式使用单例,还是您认为我可以采用更好的方式来做到这一点?

最佳答案

使用类的单个实例并不是单例模式有问题的原因。无法扩展它也没有问题。有问题的是这个单例的获取方式:

  • 它将使用单例的每个类耦合到这个具体类
  • 这使得使用单例对每个类进行单元测试基本上是不可能的,因为没有办法用模拟实例替换这个唯一的单例实例。

实现您想要的效果的更好方法是将单例传递给需要它的对象。这就是所谓的依赖注入(inject):

public class AdminConsole implements PriceProvider {
    @Override
    public Map<String, Integer> getPriceMap() {
        ...
    }
    ...
 }

public class SomeClassWhichNeedsThePrices {
    private PriceProvider priceProvider;

    public SomeClassWhichNeedsThePrices(PriceProvider priceProvider) {
        this.priceProvider = priceProvider;
    }
}

...

public static void main(String[] args) {
    AdminConsole console = new AdminConsole();
    console.initialize(); // read the prices once 
    SomeClassWhichNeedsThePrice sc = new SomeClassWhichNeedsThePrice(console);
    ...
}

现在,要对类 SomeClassWhichNeedsThePrice 进行单元测试,您可以简单地向其传递一个假的 PriceProvider,根本不需要真正的 AdminConsole:

PriceProvider fakePriceProvider = new PriceProvider() {
    @Override
    public Map<String, Integer> getPriceMap() {
        Map<String, Integer> fakePrices = new HashMap<>();
        fakePrices.put("Coke", 2);
        return fakePrices;
    }
};
// you could also use a mocking framework like Mockito

SomeClassWhichNeedsThePrice sc = new SomeClassWhichNeedsThePrice(fakePriceProvider);
assertThat(sc.computePriceForThreeCokes()).toBe(6);

关于java - 这是对单例的适当使用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25461691/

相关文章:

java - 在 Spring Data neo4j 中使用 RelationshipEntity 保存节点的正确方法是什么?

c# - 为什么这个 List.Except 在某些情况下这么慢(以及如何加快速度)?

php字符串是值类型?

java - java中的多重继承和方法覆盖问题

C# 工厂设计模式

java - 使用 Ajax 和 java ReSTLet 在客户端应用程序中流式传输视频

java - 每次在 libgdx 中单击按钮时,如何向前和向后移动 Sprite?

java - JUnit parameterized Tests 获取测试后的参数

java - 为什么 JVM 性能会随着负载的增加而提高?

c++ - 在 C++ 中寻找解决此问题的特定设计模式