通过配置文件初始化单例是否合适?
我注意到singleton的构造函数不应该有任何参数,原因是如果你需要使用参数来配置你的对象,那么可能不应该是singleton。似乎这句话非常有名,但确实存在特殊的ser case案例:
例如
我们设计了一个简单的分布式系统来处理大量的用户。查询:
显然,我们可能会设计中央服务器"作为单身人士,详情如下:
但是中央服务器需要一些配置,例如:
如何通过这些属性初始化中央服务器?
我目前的解决方案:
Configuration
的类。所以中央服务器的当前构造函数如下:
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;
}
....
....
}
Configuration类将读取和分析配置文件,以获取配置信息。
<小时/> 我的问题:
如果没有合适或不合适的初始化单身,请 提供更合适的方法
我还需要配置所有子服务器,所以似乎是配置 class太重了,我应该将Big Configuration类拆分成 两个子类? class CentralConfiguration和class 子结构
答案 0 :(得分:2)
不幸的是,你对Singelton的实现是错误的!仅仅因为它不是线程安全的。
public CentralServer getInstance() {
if (_instance == null) { // race condition possible here
_instance = new CentralServer();
}
return _instance;
}
两个线程可能会进入此关键部分并将_instance==null
评估为true,并将创建两个不同的实例。
您可以简单地静态实例化您的实例。
private final static CentralServer INSTANCE = new CentralServer();
public static CentralServer getInstance() {
return INSTANCE;
}
但是,实现singeltons的最佳方法是使用enums
public enum CentralServer { // the best way to implement singletons, due to the author of Effective Java
INSTANCE;
private CentralServer() {
}
}
这为您提供免费序列化。 但是,我不认为你需要一个singelton,singeltons通常是反模式。 Check this out
在您的代码中,CentralServer
高度依赖Configuration
,我认为这不是一件好事,您应该将配置视为依赖
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);
}
}
这将为您提供更灵活的更改或模拟配置。我认为工厂模式在这里更合适。
答案 1 :(得分:1)
初始化单身如此合适与否,如果没有,请给予 出更合适的方法:
这不是一种合适的方法,因为实现不是threadsafe而且它可以被破坏f.e.通过reflection。您应该考虑在此主题上阅读Effective Java by Joshua Bloch。
最好是创建一个枚举单例,因为这种方法对于以后的更改更灵活,具有线程安全的实例并且是不可破解的。
编辑:example。
我还需要配置所有子服务器,所以似乎是配置 class太重了,我应该将Big Configuration类拆分成 两个子类? class CentralConfiguration,类SubConfiguration?
出于配置目的,通常会在某处读取config.xml文件或config.properties文件以读取重要的预配置。创建实例后,您应该从这样的文件中提取信息,并在关闭时写出必要的更改。但与往常一样,许多方式都会导致罗马。
答案 2 :(得分:1)
在单例初始化期间使用外部资源是完全可以接受的。 Singleton
模式的普通用户是记录器,它们几乎总是从外部数据文件配置。
它确实使初始化变得更加复杂,但是制作完全可靠的单例来访问外部资源(例如配置文件)并非不可能。如果他们的配置需要数据库访问,他们甚至可以使用其他单例,例如连接池。
这个问题的其他答案正确处理了单例初始化的实际问题。