С моей точки зрения этот вопрос не так уж много показывает (скажем так, он кажется обманчиво интересным), но ответы на сопутствующие вопросы (более интересные) сами его провоцируют. Например, на вопрос "Какие вы знаете шаблоны проектирования", ответ обычно начинается с "Singleton, Factory..."
К сожалению, несмотря на то, что GoF имеет успех уже на протяжении более 15 лет, достаточно часто ответ на этом заканчивается. Кстати, на второй часто задаваемый вопрос "Чем отличается Factory от Abstract Factory" ответ дается еще реже.
Но давайте разберемся, стоит ли начинать ответ с Singleton? Наверное, не стоит. Вообще, многие считают, что Singleton - это anti-pattern. И в любом случае, Singleton - это далеко не самый интересный шаблон проектирования.
Что также хочется отметить, обычно просят реализовать просто Singleton, не упоминая ленивую инициализацию, однако почему-то на доске очень часто появляется double checked locking. Это плохой стереотип - все так делают, значит, так нужно. В реальной жизни ленивая инициализация чаще всего не требуется, а еще чаще стоимость многопоточной реализации Singleton (потому что у дополнительной синхронизации есть стоимость) превышает экономию на отложенной инициализации.
Так вот, к чему это я все? :) Проблема настолько избита, что в .NET 4.0 ввели специальный класс, который наконец-то дает нам out-of-the-box реализацию, - Lazy
1: public class LazySingleton
2: {
3: // static holder for instance, need to use lambda to construct since constructor private
4: private static readonly Lazy<LazySingleton> _instance
5: = new Lazy<LazySingleton>(() => new LazySingleton());
6:
7: // private to prevent direct instantiation.
8: private LazySingleton()
9: {
10: }
11:
12: // accessor for instance
13: public static LazySingleton Instance
14: {
15: get
16: {
17: return _instance.Value;
18: }
19: }
20: }
Всё, готово. Код честно взят отсюда. Кстати, заметьте, что код на самом-то деле глупость - у нас пустой конструктор, откладывать его исполнение за счет дополнительных синхронизаций бессмысленно.
Чуть побольше про ленивую инициализацию и Lazy
И вот казалось бы, одним вопросом для дотнетчиков меньше. Но что-то у меня есть подозрения, что вопрос еще какое-то время побудет актуальным :) Как считаете?
1го сентября - день знаний на shcoder.by :)
ОтветитьУдалитьЭто мода, сейчас все говорят это это анти-паттерн и не знают почему, и т.д. Глупость всё это, всегда что-то будет первым и всегда будут какие-то заученные модные ответа не имеющие под собой знаний. Главное не какой-то конкретный паттерн знать, а иметь голову на плечах. А все шаблонные темы на собеседованиях просто для того чтобы был объект разговора.
ОтветитьУдалитьКонечно, главное иметь голову на плечах. Я вопрос про Singleton задаю, если есть информационный повод, а так - есть и поинтереснее темы.
ОтветитьУдалитьА GoF паттерны нужно знать. В конце концов, если есть голова на плечах, то почему до сих пор не добрался до паттернов
Иметь голову на плечах это хорошо, а вот иметь голову на плечах, в которой есть понимание зачем нужны шаблоны, как они могут помочь и помогают, что характерно, в разработке и проектировании как архитектору так и программеру. Вот это и можно выяснить на собеседовании с кандидатом, и шаблоны как нельзя лучше подходят для таких целей имхо.Кстати вопрос о Singleton http://msdn.microsoft.com/en-us/library/ff650316.aspx давным давно решен %)
ОтветитьУдалитьА чем плоха реализация Singleton на с# через статик конструктор?
ОтветитьУдалитьАнонимусу
ОтветитьУдалитьПро реализацию через статический конструктор чуть-чуть здесь написано - http://www.yoda.arachsys.com/csharp/singleton.html. В общем, не совсем ленивый он, есть сложности.
To Дмитрий Гордиенко
ОтветитьУдалитьВопрос-то решен, но к сожалению не все об этом в курсе. Lazy просто сокращает количество необходимого кода. И, как я уже писал, что-то мне кажется, что даже не смотря на наличие Lazy все равно будут приходить и писать что-то непонятное.
Если вы спрашиваете про синглетон на собеседованиях и припоминаете многопоточность, то примите ли ответ с двойной проверкой?
ОтветитьУдалитьКак было указано выше, двойная блокировка вполне себе работает, просто нужно не забыть про volatile.
ОтветитьУдалитьНу и если с этим вопросом не получается, то это не конец света. Я бы сказал так - я рад, когда получается, когда есть проблемы - переходим к следуещему.
Да и на практике вообще достаточно знать, что все не так просто, и google под рукой.
>Как было указано выше, двойная блокировка вполне себе работает
ОтветитьУдалитьВсё-таки не "двойная блокировка" (блокировка-то одна), а "двойная проверка" (до блокировки и после) ;о) не оплошайте на собеседовании :о)
Ну хорошо, а то мне как-то на одном собеседовании сказали, что двойная проверка не работает (подразумевая видимо какую-то прочитанную ошибочную статью в тырнете) но вот объяснить - почему не работает так и не смогли :о) аргументировали "на некоторых многопроцессорных системах" - это всё-таки не разговор.
Да и "немногопоточного" синглетона не бывает: общепринятой практикой является делать thread-safe доступ к статическим данным.
Так же по поводу ленивости - вы не показали ещё один пример с вложенным статическим классом, который позволяет обходиться без Lazy уже подчти десяток лет ;о)
Спсб, двойная проверка, да :) Double-checked locking может не работать без volatile, а так же в лохматых версиях джавы и может быть .net.
ОтветитьУдалитьЯ не показывал все возможные варианты - их можно найти в интернете - хотелось просто показать про общие проблемы и про новый класс Lazy.
Сабж для .NET от MS никогда проблемой не был (в Mono возможно будет по другому). В CLR есть средства для этого - гуглим по ключевому слову "beforefieldinit"
ОтветитьУдалитьXna, решений этой задачи много, проблема в том, что очень многие их не знают.
ОтветитьУдалить