2013-09-17 2 views
0

Я хотел бы найти краткий реализатор C# для шаблона Singleton, и мне интересно, поддерживает ли он следующий сценарий. Что, если частный конструктор singleton, как часть инициализации экземпляра, вызывает конструктор, который сам пытается получить доступ к инициализации singleton? Это то, что я имел в виду под reentrancy в названии этого вопроса. Некоторые сказали бы, что конструктор не должен делать ничего сложного, что может привести к этому. Но что, если из-за некоторого будущего изменения кода внутри вызываемых конструкторов это произойдет?Concise Singleton impl, поддерживающий reentrancy

Я просмотрел различные ответы на this question. Я впечатлен кратностью использования Lazy<T>. В используемом случае я смотрю его, он генерирует исключение, которое намного лучше, чем создание двух экземпляров синглтона. Но, увы, при выдаче исключения он отключает приложение, что означает, что он не поддерживает целевой сценарий.

class Apple 
{ 
    static readonly Lazy<Apple> instance = new Lazy<Apple>(() => new Apple(), true); 
    public static Apple Instance { get { return instance.Value; } } 

    private Apple() 
    { 
     // Call other methods which might access Instance... 
     var testGet = Instance; 
    } 
} 

У меня есть идея вместо этого сделать следующее.

class Banana 
{ 
    static Banana instance; 
    public static Banana Instance { get { return instance ?? new Banana(); } } 

    private Banana() 
    { 
     instance = this; 
     // Then call other methods which might access Instance... 
     var testGet = Instance; 
    } 
} 

Он поддерживает целевой сценарий, но что-то не так? Есть ли лучшее решение?

Обратите внимание на следующее, прежде чем отправлять ответ. Как и многие люди, я все еще рассматриваю Синглтон как образец. Многие энтузиасты DI любят называть это анти-шаблоном. В контексте проекта, который опирается на DI/IoC, это разумное утверждение. Однако вне этого контекста Синглтон по-прежнему является действующим шаблоном проектирования. Я не использую DI, и я не заинтересован в обсуждении его достоинств. Пожалуйста, не публикуйте ответ ниже, если он будет ссылаться на Singleton как на «анти-шаблон», или если он предложит «инъекцию зависимостей» в качестве решения. Заранее спасибо.

+1

Должен ли этот класс поддерживать доступ из нескольких потоков? Если это так, ваше решение не справляется с этим. – Servy

+3

Мне кажется, что вы настроены на включение одного анти-шаблона (с использованием объекта до его полной сборки) в рамках другого анти-шаблона (шаблон singleton, который имеет проблемы, выходящие за пределы только DI). Включение этого * на всякий случай * вы получите ужасное требование (которое, вероятно, должно спровоцировать редизайн в любом случае), не кажется хорошей идеей. –

+0

@JonSkeet «Метод», вызванный внутри частного конструктора, фактически является другим конструктором. Вызов это всего лишь часть инициализации экземпляра. Насколько я знаю, это довольно обычная практика, а не «анти-образец». – HappyNomad

ответ

1

Несмотря на то, что Singleton не может рассматриваться как анти-шаблон, доступ к членам экземпляра до того, как этот экземпляр будет полностью построен - это анти-шаблон. Вы не можете гарантировать, что код, открытый для инициализируемого класса, не пытается использовать некоторое неинициализированное состояние. Таким образом, этот сценарий должен поддерживаться не. Если код, который пытается получить доступ к синглтону, позже добавляется к конструкторам, вызываемым конструктором singleton, то это должно вызвать повторную конструкцию.

Использование Lazy<T> как Apple демонстрирует лучший подход, поскольку он генерирует исключение при повторном входе, а не доступ к неполному экземпляру. Lazy<T> дополнительно поддерживает доступ из нескольких потоков, если это необходимо.

Смежные вопросы