单身替换?

时间:2010-03-10 15:14:42

标签: c# singleton

在我的senario中,我有一个全局设置对象,比如GlobalSettings,它有一个静态属性“Current”(单例),并且应该只有一个GlobalSettings实例。

但是......在我的数据模型中,有一个实体“LocalizedContent”:

public class LocalizedContent {
     public string Title { get; set; }
     public string Content { get; set; }
     public string CultureName { get; set; }
}

在构造函数中,我想通过将CultureName设置为系统的默认文化来初始化实例,并且我可以从GlobalSettings.Current.DefaultCultureName获取默认文化名称。

但是,我不想在LocalizedContent类中使用单例属性“GlobalSettings.Current”,因为它会导致强耦合。所以我的问题是,在哪里设置这个默认文化名称的正确位置?

提前致谢!

3 个答案:

答案 0 :(得分:6)

为什么不向LocalizedContent添加一个以DefaultCultureName作为参数的构造函数?

然后可以重新使用LocalizedContent而不依赖GlobalSettings

答案 1 :(得分:3)

我认为这里的技巧是在LocalizedContent类中添加一个构造函数,它接受需要消耗的值。

public LocalizedContent {
  public LocalizedContent(string cultureName) {
    this.CultureName = cultureName;
  }
}

为方便起见,您还可以添加一个帮助方法,该方法使用LocalizedContent值创建GlobalSettings方法。

public static LocalizedContent CreateLocalizedContent() {
  return new LocalizedContent(GlobalSettings.Current.DefaultCultureName);
}

答案 2 :(得分:1)

嗯,您可以查看this

简而言之,您希望将注入“文化”源添加到您的本地化内容对象中。请考虑以下示例

// your public global settings singleton, no big surprises here
// except possibly thread safe locking [shrug] if you are singlethreaded
// you can simplify this model further
public class GlobalSettings
{
    // singleton synchronization and instance reference
    private static readonly object _instanceSyncRoot = new object ();
    private static readonly GlobalSettings _instance = null;

    // instance-based synchronization and values
    private readonly object _syncRoot = new object ();
    private string _cultureName = string.Empty;

    // gets public static instance
    public static GlobalSettings Current
    {
        get
        {
            lock (_instanceSyncRoot)
            {
                if (_instance == null)
                {
                    _instance = new GlobalSettings ();
                }
            }
            return _instance;
        }
    }

    // gets public culture name
    public string CultureName 
    {
        get { lock (_syncRoot) { return _cultureName; } }
        set { lock (_syncRoot) { _cultureName = value; } }
    }

    // private constructor to re-inforce singleton semantics
    private GlobalSettings () { }
}

所以,很多事情。通常这样的单身人士不赞成 - 他们非常方便!但正如您所指出的那样,导致功能组件和配置之间的紧密耦合。

如果你想摆脱这种紧密耦合,同时保留存在的东西,你有几个选择,最容易

// define a general-purpose settings interface, i do not much
// care for refactor tools, but you may use re-sharper or built in
// refactor components to "extract" those properties from global
// settings that you need. here we pull out culture name only,
public interface ISettings
{
    // gets culture name from underlying settings implementation
    string CultureName { get; }
}

public class LocalizedContent
{
    public string CultureName { get; set; }
    public LocalizedContent (ISettings settings)
    {
        CultureName = settings.CultureName;
    }
}

如果您能够修改GlobalSettings单身,

// public singleton is now an implementation of a "loosely coupled
// component" called ISettings
public class GlobalSettings : ISettings { ... }

// elsewhere in code
public LocalizedContent GetLocalizedContent ()
{
    LocalizedContent content = new LocalizedContent (GlobalSettings.Instance);
    return content;
}

如果您无法修改GlobalSettings单身,

// wrapper class for global settings singleton
public class Settings : ISettings
{
     public string CultureName 
     {
         get { return GlobalSettings.Instance.CultureName; }
     }
}

// elsewhere in code
public LocalizedContent GetLocalizedContent ()
{
    LocalizedContent content = new LocalizedContent (new Settings ());
    return content;
}

现在,LocalizedContent不再与GlobalSettings单身紧密耦合。实际上,ISettings的任何实现都将满足其构造函数依赖性。

如果你的依赖关系像一两个字符串一样简单,那么这可能是过度的。但是,如果您有其他复杂组件依赖于此全局单例,则此方法可能适合您:)