Как реализовать Singleton, когда существует объектная зависимость при создании экземпляра? - PullRequest
2 голосов
/ 08 июля 2011

У меня есть одноэлементный класс, для которого требуется создать экземпляр объекта.

Я использую этот метод для этого:

  public static AppConfig Instance(IConfigManager configManager)
    {
        if (_instanceHolder == null)
        {
            lock (LockObject)
            {
                if (_instanceHolder == null)
                {
                    _instanceHolder = new AppConfig(configManager);
                }
            }
        }

        return _instanceHolder;
    }

Это лучший способ реализовать одноэлементный втакой сценарий?

Спасибо

Ответы [ 5 ]

6 голосов
/ 08 июля 2011

На мой взгляд, использование синглтона в этой ситуации кажется очень плохой идеей. Второй вызов полностью игнорирует параметр configManager, потому что он обнаружит, что уже есть экземпляр. Это нарушает принцип наименьшего удивления, ИМО.

Шаблон синглтона , как правило, неприятен по разным причинам, не в последнюю очередь из-за возможности тестирования Этот пример еще хуже - определенно отойдите от него.

Кроме того, я бы в любом случае не использовал двойную проверку блокировки при реализации шаблона синглтона. См. мою статью о шаблоне синглтона для моего предпочтительного выбора.

2 голосов
/ 08 июля 2011

Кажется, что контейнер IoC очень хорошо подходит для этого сценария, например (с использованием Ninject ).

IKernel kernel = new StandardKernel();
// register implementor of IConfiguration
kernel.Bind<IConfiguration>().To<Config>();
// register AppConfig as a singleton
kernel.Bind<AppConfig>().ToSelf().InSingletonScope();

...

// get the AppConfig singleton
var appConfig = kernel.Get<AppConfig>();
0 голосов
/ 11 июля 2011

Следуя рекомендации Джона:

 public static void Initialize(IConfigManager configManager)
    {
        if (_instanceHolder == null)
        {
            lock (LockObject)
            {
                if (_instanceHolder == null)
                {
                    _instanceHolder = new AppConfig(configManager);
                    return;
                }
            }
        }

        throw new ApplicationException("Initalize() method should be called only once.");
    }

    /// <summary>
    /// Instances the specified config manager.
    /// </summary>
    /// <returns></returns>
    public static AppConfig Instance
    {
        get
        {
            if (_instanceHolder == null)
            {
                throw new ApplicationException("Singleton instance hasn't been initialized.");
            }

            return _instanceHolder;
        }
    }

, и я призываю это:

        void Application_Start(object sender, EventArgs e)
    {
        AppConfig.Initialize(new ConfigManagerWrapper());
    }

В идеале я должен использовать для этого контейнер IoC.Но мне понравилось, что класс AppConfig должен иметь реализацию по умолчанию, а также позволял использовать его для внедрения зависимостей.В этом случае мне не нужно было вызывать метод Initialize () на производстве.

0 голосов
/ 08 июля 2011

Обычно, когда я использую синглтон, это только для рефакторинга от большего зла, а именно класса, полного статических методов. Одна хитрость, которую я использовал, когда мне нужно передать зависимость для построения, - это иметь два метода «экземпляра» (или метод «конструкция» и «экземпляр»): один принимает аргумент, а другой нет. Тот, который принимает аргумент, должен быть вызван первым, и при повторном вызове выдаст ошибку. Версия без параметров выдаст ошибку, если она вызывается раньше другой.

Это означает, что вы должны быть осторожны при использовании синглтона, но, по крайней мере, вы должны быстро выяснить во время выполнения, если вы делаете это неправильно. Я надеюсь (как в моем, так и в вашем случае), что это всего лишь шаг на пути к чему-то лучшему.

Я использую Java, но я предполагаю, что в C # все работает примерно так же.

0 голосов
/ 08 июля 2011

Это двойная проверка шаблона Singletone.Здесь нет проблем.

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