2014-08-30 50 views
0

通過配置文件初始化單例是否合適?通過配置文件初始化一個「singleton」是否合適?

我注意到singleton的構造函數不應該有任何參數,原因是如果你需要使用參數來配置你的對象,可能不應該是singleton。看起來這句話非常有名,但確實有一些特殊的誹謗案例:

例如 我們設計了一個簡單的分佈式系統,以處理大量用戶查詢:

  • 只有一箇中央服務器
  • n個子服務器,每個子服務器連接到中央服務器
  • 有子之間沒有任何連接服務器

顯然,我們可以設計的「中央服務器」爲單身,詳情如下:

  • enum ServerType;
  • 抽象類服務器;
  • class CentralServer從Server繼承;(CentralServer是單例)
  • class SubServer繼承自Server;
  • class Query;
  • ... ... ...

但中央服務器需要一些配置,如:

  • 服務器名
  • 描述
  • 端口編號,ip地址地圖
  • 其子服務器列表
  • BlockingQueue的大小
  • ... ... ...

如何通過這些屬性初始化中央服務器?
我目前的解決方案:

  • 使用配置文件來完成這部分工作。
  • 我定義了另一個類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 CentralConfiguration和類 SubConfiguration?

回答

2

不幸的是,你對Singelton的實現是錯誤的!只是因爲它不是線程安全的。

public CentralServer getInstance() { 
    if (_instance == null) { // race condition possible here 
     _instance = new CentralServer(); 
    } 
    return _instance; 
} 

兩個線程可能進入這個關鍵部分,並評估_instance==null爲真,和兩個不同的實例將被創建。 你可以簡單地實例化你的實例。

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

在你的代碼,CentralServerConfiguration高度依賴,我不認爲這是一件好事,你應該看到的配置作爲一個依賴

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

初始化單這樣的合適與否,如果沒有,請給 出更合適的方法:

這是不是一個合適的方法,因爲執行不threadsafe但它可以打破fe通過reflection。您應該考慮閱讀Effective Java by Joshua Bloch關於此主題。

更好的辦法是創建一個枚舉單例,因爲這種方法對於以後的更改更加靈活,具有線程安全instanciating並且是不可破解的。

編輯:example

我還需要配置所有的子服務器,所以似乎配置 類是太重了,我應該分裂大配置類爲 兩個子類?類CentralConfiguration和類SubConfiguration?

出於配置的目​​的,通常會有一個config.xml文件或一個config.properties文件來讀取重要的預配置。創建實例後,應該從這樣的文件中提取信息並在關閉時寫出必要的更改。但一如既往,許多方式導致羅馬。

1

在單例初始化期間使用外部資源是完全可以接受的。 Singleton模式的常見用戶是記錄器,它們幾乎總是由外部數據文件配置。

它確實會使初始化變得更加複雜,但是製作一個完全踩踏安全的單件來訪問外部資源(如配置文件)並非不可能。如果他們的配置需要數據庫訪問,他們甚至可以使用其他單例,如連接池。

這個問題的其他答案正確地處理了你的單例初始化的實際問題。