Замена синглтона? - PullRequest
       13

Замена синглтона?

2 голосов
/ 10 марта 2010

В моем senario, у меня есть объект глобальной настройки, скажем, GlobalSettings, у него есть статическое свойство "Current" (singleton) и должен быть только один экземпляр GlobalSettings.

Но ... В моей модели данных есть сущность "LocalizedContent":

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

В конструкторе я хочу инициализировать экземпляр, установив CultureName в культуру системы по умолчанию, и я могу получить имя культуры по умолчанию из GlobalSettings.Current.DefaultCultureName.

Однако я не хочу использовать одноэлементное свойство "GlobalSettings.Current" в классе LocalizedContent, так как это приведет к сильной связи. Итак, мой вопрос, где находится правильное место для установки этого имени культуры по умолчанию?

Заранее спасибо!

Ответы [ 3 ]

6 голосов
/ 10 марта 2010

Почему бы не добавить конструктор к LocalizedContent, который принимает DefaultCultureName в качестве параметра?

LocalizedContent может затем использоваться повторно без зависимости от GlobalSettings.

3 голосов
/ 10 марта 2010

Я думаю, что хитрость в том, чтобы добавить конструктор к классу LocalizedContent, который принимает значения, которые ему необходимы.

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

Для удобства вы также можете добавить вспомогательный метод, который создает метод LocalizedContent с использованием значений GlobalSettings.

public static LocalizedContent CreateLocalizedContent() {
  return new LocalizedContent(GlobalSettings.Current.DefaultCultureName);
}
1 голос
/ 10 марта 2010

Хм, вы можете проверить это .

Короче говоря, то, что вы хотели бы сделать, это вставить источник "культуры" в ваш локализованный объект контента. Рассмотрим следующий пример:

// 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 singleton,

// 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 singleton,

// 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 будет удовлетворять своей зависимости от конструктора.

Если ваши зависимости так же просты, как строка или две, это может быть излишним. Однако, если у вас есть другие сложные компоненты, зависящие от этого глобального синглтона, этот подход может быть для вас:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...