Страницы

Поиск по вопросам

воскресенье, 29 декабря 2019 г.

Простая реализация паттерна Singletone на c#

#c_sharp #шаблоны_проектирования


Разбираюсь сейчас Singletone, нашел в сети несколько разных реализаций, но так и
не понял, как они работают. Синглтон - это паттерн, который гарантирует наличие только
одного экземпляра класса, а в примерах я немного не понимаю, как эта "гарантия" реализуется.
Первый пример

public sealed class MySingleton  {  
static MySingleton myInstance = null;  

MySingleton()  
{  
}  

public static MySingleton MyInstance  
{  
    get  
    {  
        if (myInstance = = null)  
        {  
            myIinstance = new MySingleton();  
        }  
        return myInstance;  
    }  
    private set;  
    }
}  


Второй пример:

class Singleton
{  
   static Singleton obj;    
   public static Singleton Obj { get { return obj; } }   
   public string Data { get; set; }     
   static Singleton()  
   {  
      obj = new Singleton();  
   }    
   private Singleton()  
   {
      Data = "I am a singleton";  
   }
}

//вызов
{  
   static void Main(string[] args)   
   {  
      Singleton s1 = Singleton.Obj;  
      Console.WriteLine(s1.Data);   
   }
}


Собственно, можете объяснить чем эти два примера отличается друг от друга, и как
они гарантируют наличие одного экземпляра класса? Или они оба неправильны, и есть более
простая и понятная реализации паттерна на c#?
    


Ответы

Ответ 1



Гарантия реализуется за счет того, что класс Singleton не предоставляет никаких других способов получения экземпляра, кроме статического свойства - а свойство написано так, что двух разных экземпляров никогда не отдаст. Обратите внимание на приватный конструктор - для синглтонов это очень важно. Отличие между приведенными примерами в том, что первый вариант создает экземпляр по требованию - второй же создает свой экземпляр при инициализации класса. Вообще говоря, так как инициализация класса в .NET, в свою очередь, также происходит по требованию - различие тут не очень-то и велико. Еще если отличия в потокобезопасности - для статических конструкторов потокобезопасность гарантируется средой, а вот первый вариант синглтона может работать только в однопоточной среде. По поводу простых примеров - вот так синглтоны обычно пишу я: public class Foo { private Foo() { } public static readonly Foo INSTANCE = new Foo(); // ... } По сути, это второй вариант - но выглядит он куда проще. Тут просто создается неизменяемая статическая переменная, и ничего больше. PS Современные тенденции - избегать синглтонов; не следует делать синглтонами все подряд. Перед тем как некоторый класс сделать синглтоном, задумайтесь: а что страшного случится если кто-то (возможно, вы сами) создаст второй экземпляр этого класса? В большинстве случаев, ответ - "да ничего не случится". Если это так - не надо делать класс синглтоном.

Ответ 2



Примеры синглтонов, которые используются в .NET Framework, можно посмотреть в исходниках .NET Framework Простая реализация синглтона: public class Data { public static readonly Data Instance = new Data(); private Data() { } } Если Data - это большой объект, и его надо создавать по-требованию, то можно использовать Lazy public class Data { static readonly Data _Instance = new Lazy(() => new Data(), LazyThreadSafetyMode.PublicationOnly); public static Data Instance { get { return _Instance.Value; }} private Data() { } }

Ответ 3



Простая реализация - использование Lazy. Как раз именно с Lazy задумываться над всеми этими многопоточными реализациями уже не приходится, работает из коробки. Код отсюда: public sealed class Singleton { private static readonly Lazy instanceHolder = new Lazy(() => new Singleton()); private Singleton() { ... } public static Singleton Instance { get { return instanceHolder.Value; } } } Я под синглтон использую обычно класс настроек программы. Ну т.е. у них есть метод Save и куча полей, которые мне нужны в рантайме. Если вдруг когда то мне захочется добавить профили настроек - достаточно расшить точку Instance, а не переписывать абсолютно все обращения к настройкам в коде, в этом преимущество. Разница со статик классами небольшая, но мне например в статик классах постоянно мешает то, что расшивать их обычно очень неудобно. Плюс, хранить два экземпляра статик класса в качестве двух профилей настроек уже не получится. Тогда как тупая сериализация инстанса - вполне рабочее решение.

Комментариев нет:

Отправить комментарий