这是单身人士的恰当用途吗?

时间:2014-08-23 11:58:40

标签: java performance design-patterns configuration singleton

我最近一直在阅读单身人士往往是一种被滥用的设计模式。我知道全局可以是坏的,单身人士不可扩展(因此不是好的OO设计),但我想知道在这种情况下我是否正确使用它&#39;。< / p>

基本上,我有一些软件正在运行 - 比方说 - 自动售货机。它有一个管理员控制台,您可以在其中登录和配置一些东西。例如,今天我想要一个售价3美元的可乐瓶和一个花费2美元的精灵,所以我可以登录到这个管理控制台并编辑这些值。然后,在我的代码中,我可以使用一些java代码从控制台读取这些配置参数:

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

这会加载Coke:3,Sprite:2,Water:2和。之类的关键值对的映射 当主要&#39; class首先在机器启动时实例化。

只有在重置硬件时才能更新饮料的价格。

现在,因为这台自动售货机的硬件非常有限,并且从控制台中提取设置非常耗费内存,所以我想要做到这一点。

当AdminConsole被实例化时,它会从管理控制台中提取这些值并生成地图。拉动这些值的行为是一种记忆昂贵的操作,而地图并不是那么重要。因此,我想在代码中做的是使AdminConsole成为单例,因此它只能实例化一次。这是因为当新开发人员加入团队并且不知道在内存有限的硬件上进行内存昂贵的操作时,他不会意外地多次实例化它。

相反,它看起来像这样:

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

那么,你认为我认为我在这里以一种好的方式使用单身人士,或者你认为我有更好的方法来做这件事吗?

2 个答案:

答案 0 :(得分:2)

使用类的单个实例并不会导致单例模式出现问题。无法扩展它也没有问题。有问题的是获得这个单一实例的方式:

  • 它将使用单身人士的每个班级与这个具体的班级相结合
  • 它基本上不可能使用单例对每个类进行单元测试,因为无法用模拟实例替换这个唯一的Singleton实例。

实现目标的更好方法是将单例传递给需要它的对象。这称为依赖注入:

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);

答案 1 :(得分:2)

我查看了Stack Overflow上的Singleton模式讨论,虽然我看到99.9%的人认为Singleton是世界上所有邪恶的根源我偶然发现post可能对你有帮助。如果你阅读整个讨论,你会发现每个人对主要关键词(花哨的程序员单词)的单身人士有自己的想法,如单元测试依赖注入反转控制