2010-09-01 50 views
4

我創建了一個類,它允許訪問全局變量,而只創建一次,實質上是一個單例。我創建的這個單例有什麼問題

但是,它不符合任何'正確'的方式來實現一個單身人士。我認爲它沒有提到,因爲它有一些'錯誤',但我不能看到任何問題,除了缺乏延遲初始化。

有什麼想法?

static class DefaultFields 
{ 
    private static readonly string IniPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "defaultFields.ini"); 
    private static readonly IniConfigSource Ini = GetIni();    

    /// <summary> 
    /// Creates a reference to the ini file on startup 
    /// </summary> 
    private static IniConfigSource GetIni() 
    { 
     // Create Ini File if it does not exist 
     if (!File.Exists(IniPath)) 
     { 
      using (FileStream stream = new FileStream(IniPath, FileMode.CreateNew)) 
      { 
       var iniConfig = new IniConfigSource(stream); 
       iniConfig.AddConfig("default"); 
       iniConfig.Save(IniPath); 
      } 
     } 

     var source = new IniConfigSource(IniPath); 
     return source; 
    } 

    public static IConfig Get() 
    { 
     return Ini.Configs["default"]; 
    } 

    public static void Remove(string key) 
    { 
     Get().Remove(key); 
     Ini.Save(); 
    } 

    public static void Set(string key, string value) 
    { 
     Get().Set(key, value ?? ""); 
     Ini.Save(); 
    } 
} 
+0

參考http://stackoverflow.com/questions/3532161/what-is-the-difference-between-a-singleton-pattern-and-a-static-class-in-java – Numenor 2010-09-01 14:50:59

回答

5

它不遵循通常的單例模式,因爲你的類是靜態的,只是控制對靜態變量的訪問。

作爲單例通常是一個類的靜態單個實例,其中唯一的靜態函數是創建和訪問將變量存儲爲常規非靜態成員變量的單例。

含義類可以很容易地被改變或作出被實例更多然後一次,但你不能

+0

我試圖避免在幾個不同的地方聲明'IniConfigSource',所以我只是將它聲明在一個類中,而只是將它聲明。 能夠使用Default.Get()等等,而不必一次又一次地定義這些變量是我的目標。 我明白靜態類和這樣的工作是如何正常工作的,我只是混淆了靜態變量的工作原理,並認爲我所做的必須是一種單例。 由於它不是一個單身人士,我沒有任何特別的願望,所以我認爲它很好,除了像'rwmnau'所暗示的那樣添加一些鎖定。 – John 2010-09-01 20:15:51

2

您班上的所有方法都是靜態的,所以您隱藏了用戶的單個實例。通過singleton pattern單個實例通過公共屬性公開,通常稱爲Instance(在Java等其他語言中,它可能是一種名爲getInstance或類似的方法)。

alt text

您的代碼是沒有錯的 - 它只是不Singleton模式。如果你想實施一個單身人士,我會推薦Jon Skeet的文章Implementing the Singleton Pattern in C#

2

我看到的最大的問題是你沒有做任何SyncLock -ing各地寫入您的INI文件 - 嘗試同時寫入數值的多個線程最終會導致不可預知的結果,例如同時寫入數據和只有一個持久數據(或者多個線程試圖一次寫入文件,導致IO錯誤)。

我會創建某種私有的「鎖定」對象,然後將寫入文件包裝到SyncLock中,以確保一次只有一個線程能夠更改值(或者至少,將更改提交給INI文件)。

+0

我同意,缺少鎖定可能是一個問題。 'IConfig'實現可能會在其Remove和Set方法中執行鎖定,但由於此代碼不知道該實現是什麼,因此我會說DefaultFields類應該執行鎖定本身。 – 2010-09-01 14:59:32

+0

+1好主意謝謝。 – John 2010-09-01 20:16:16

4

你對單身人士是正確的,它是一個具有提供全局訪問的獨特實例的類。

它可能看起來像一個靜態類,但通常以不同的方式實現它。

還要記住,這種模式應該使用一些預防措施,因爲一旦深入代碼中它很難重構單例。主要應用於有硬件限制或實現對工廠的唯一訪問點。我會盡可能避免它。

的實現的一個示例是如下:

public class A 
{ 
    /// <summary> 
    /// Unique instance to access to object A 
    /// </summary> 
    public static readonly A Singleton = new A(); 

    /// <summary> 
    /// private constructor so it can only be created internally. 
    /// </summary> 
    private A() 
    { 
    } 

    /// <summary> 
    /// Instance method B does B.. 
    /// </summary> 
    public void B() 
    { 
    } 
} 

而且可以像

A.Singleton使用。B()

希望有所幫助。

0

這不是一個單身人士,它是一個靜態類。

在很多方面,靜態類與單例類似,爲true。但是靜態類不能實現接口,不能從基類繼承功能,並且不能對它們進行引用。

0

爲什麼只讀Ini字段?

但是如果你想實現單件模式,它是這樣的:

static DefaultFields 
{ 
    private readonly string IniPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "defaultFields.ini"); 
    private readonly IniConfigSource Ini = GetIni();    

    private static DefaultFields _default; 

    public static DefaultFields Default 
    { 
     get { if(this._default == null){ this._default = new DefaultFields(); } return this._default; } 
    } 

    private DefaultFields() 
    { 

    } 

    /// <summary> 
    /// Creates a reference to the ini file on startup 
    /// </summary> 
    private IniConfigSource GetIni() 
    { 
     // Create Ini File if it does not exist 
     if (!File.Exists(IniPath)) 
     { 
      using (FileStream stream = new FileStream(IniPath, FileMode.CreateNew)) 
      { 
       var iniConfig = new IniConfigSource(stream); 
       iniConfig.AddConfig("default"); 
       iniConfig.Save(IniPath); 
      } 
     } 

     var source = new IniConfigSource(IniPath); 
     return source; 
    } 

    public IConfig Get() 
    { 
     return Ini.Configs["default"]; 
    } 

    public void Remove(string key) 
    { 
     Get().Remove(key); 
     Ini.Save(); 
    } 

    public void Set(string key, string value) 
    { 
     Get().Set(key, value ?? ""); 
     Ini.Save(); 
    } 
} 
0

我對這個問題的答案爲好。在我看來,有大量單例實例使用了懶惰實例化,但我認爲你必須問自己,是否真的有必要逐個案例研究。

儘管本文涉及Java,但這些概念仍應適用。這爲不同的單例實現提供了許多例子。 http://www.shaunabram.com/singleton-implementations/

我也見過很多關於「Effective Java」一書的內容,第71條 - 明智地使用了懶惰實例。基本上,除非需要,否則不要這樣做。

0

延遲初始化對於單例類非常重要。通過聲明你的類是靜態的,你需要實現一個靜態類,而不是一個單獨的類。