首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >通过配置文件初始化“单例”是否合适?

通过配置文件初始化“单例”是否合适?
EN

Stack Overflow用户
提问于 2014-08-30 22:26:57
回答 3查看 815关注 0票数 0

通过配置文件初始化单例是否合适?

我注意到单例的构造函数不应该有任何参数,原因是如果您需要使用参数来配置对象,那么很可能不应该是单例。这句话似乎很有名,但确实有一些役例是特殊的:

例如,我们设计了一个简单的分布式系统来处理大量的用户查询:

  • 只有一个中央服务器
  • N个子服务器,每个子服务器连接到中央服务器。
  • 子服务器之间没有连接。

显然,我们可以将“中央服务器”设计为“单例”,具体如下:

  • 明矾ServerType;
  • 抽象类服务器;
  • 类CentralServer从服务器继承;(CentralServer是单例)
  • 类SubServer从服务器继承;
  • 类查询;
  • ...

但是中央服务器需要一些配置,例如:

  • serverName
  • 描述
  • portNum-ipAddress映射
  • 其子服务器的列表
  • BlockingQueue的大小
  • ...

如何通过这些属性初始化中心服务器?

我目前的解决方案:

  • 使用配置文件完成此部件作业。
  • 我定义了另一个名为Configuration的类。

因此,中央服务器的当前构造函数如下:

代码语言:javascript
复制
class CentralServer extends Server implements Runnable, ....... {
    ....
    ....
    private static CentralServer _instance;
    private CentralServer () {
        super();
        .... 
        serverName = Configuration.getCentralServerName();
        description = Configuration.getCentralServerDescription();
        Configuration.initCentralServerPortNumIpMap(portNumIpMap);
        Configuration.initCentralServerSubServersList(subServersList);
        sizeBlockingQueue = Configuration.initCentralServerBlockingQueueSize();
        ....
    }

    public CentralServer getInstance() {
        if (_instance == null) {
            _instance = new CentralServer();
        }
        return _instance;
    }
    ....
    ....
}

配置类,将读取和分析配置文件,以获取配置信息。

我的问题是:

  • 初始化这样的单例是否合适,如果不是,请给出更合适的方法。
  • 我还需要配置所有的子服务器,所以似乎配置类太重了,应该将大配置类划分为两个子类吗?CentralConfiguration类和SubConfiguration类?
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2014-08-30 22:53:34

不幸的是,您对Singelton的实现是错误的!!仅仅因为它不是线程安全的。

代码语言:javascript
复制
public CentralServer getInstance() {
    if (_instance == null) {   // race condition possible here 
        _instance = new CentralServer();
    }
    return _instance;
}

两个线程可能进入这个关键部分并将_instance==null计算为true,并且将创建两个不同的实例。您可以简单地静态地实例化实例。

代码语言:javascript
复制
private final static CentralServer INSTANCE = new CentralServer();

public static CentralServer getInstance() {
    return INSTANCE;
}

然而,实现单However的最佳方法是使用enums

代码语言:javascript
复制
public enum CentralServer { // the best way to implement singletons, due to the author of Effective Java  
INSTANCE;

private CentralServer() {
}
}

这使您可以免费序列化。然而,我认为你根本不需要一个单子,单子通常是反模式的。看看这个

在您的代码中,CentralServerConfiguration有很高的依赖性,我认为这不是一件好事,您应该将配置视为依赖关系

代码语言:javascript
复制
class CentralServer{
 private final Configuration serverConf;

 private CentralServer(Configuration serverConf){  // inject configuration
   this.serverConf = serverConf;
 }
 public static CentralServer createCentralServer(Configuration serverConf){ // static factory perhaps
  return new CentralServer(serverConf);
 }
}

这将为您提供更改或模拟配置的更大灵活性。我认为工厂模式在这里更合适。

票数 2
EN

Stack Overflow用户

发布于 2014-08-30 22:50:12

初始化这样的单身人士是否合适,如果不合适,请给出更合适的方法:

这不是一种合适的方法,因为实现还不是线程安全,而且可以破坏f.e。通过反射。您应该考虑阅读有关此主题的约书亚·布洛赫的有效Java

最好是创建一个enum,因为这种方法对于以后的更改更加灵活,具有threadsafe实例化,并且不可中断。

编辑:示例 .

我还需要配置所有的子服务器,所以似乎配置类太重了,应该将大配置类划分为两个子类吗?CentralConfiguration类和SubConfiguration类?

为了进行配置,通常会有一个config.xml文件或一个config.properties文件来读取重要的预配置。在创建实例之后,您应该从这样的文件中提取信息,并在关闭时写出必要的更改。但和往常一样,很多方式都通向罗马。

票数 1
EN

Stack Overflow用户

发布于 2014-08-30 22:55:09

在初始化单例时使用外部资源是完全可以接受的。Singleton模式的一个常见用户是记录器,它们几乎总是通过外部数据文件配置的。

它确实使初始化变得更加复杂,但要使完全安全的单例访问外部资源(如配置文件)并不是不可能的。如果它们的配置需要数据库访问,它们甚至可以使用其他的单件,例如连接池。

这个问题的其他答案正确地处理了单例初始化的实际问题。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25587264

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档