2010-09-01 48 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

延迟初始化对于单例类非常重要。通过声明你的类是静态的,你需要实现一个静态类,而不是一个单独的类。