четверг, 10 июля 2014 г.

Singleton vs static class

Singleton чи static class

Дуже часто на співбесідах запитують яка різниця між статичним класом та сінглтоном. Як правило таке питання не завдає труднощів, адже на просторах інтернету дуже багато відповідей. Зазвичай ми чуємо щось на кшталт: сінглтон це класс який існує лише в одному екземплярі, і далі розповідь про обмеження статичного класу…
Спробую описати дещо з іншого боку. Статичний клас мені нагадує структурне програмування. А сінглтон це об’єкт, значить це вже ООП. А раз ООП, то ми можемо наслідувати сінглтон від інших класів, інтерфейсів, можемо використовувати об’єкт в Dependency Injection, та навіть з деякими «костилями» унаслідуватись від сінглтона.


public abstract class Keyboard<TDerivedType> where TDerivedType : class
{
    private static TDerivedType _instance;

    public static TDerivedType Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = (TDerivedType)Activator.CreateInstance(
                    typeof(TDerivedType), true);
            }
            return _instance;
        }
    }
}

public class UsbKeyboard : Keyboard<UsbKeyboard>
{
    private UsbKeyboard()
    {
    }
}

До речі, про ініціалізацію. Як видно в сінглтоні ми можемо керувати часом створення об’єкту (навіть можливо керувати і часом знищення об’єкту, але не потрібно :) ). В статичному класі керувати часом ініціалізації класу не можна: статичний конструктор буде автоматично виконаний при доступі до будь якого поля члена статичного класу (але не факт http://habrahabr.ru/post/125421/), крім константи. Також потрібно зауважити, що статичний конструктор гарантовано буде виконаний лише один раз в розрізі аплікейшн домену. Тож в multithreaded програмах для статичних конструкторів (не має різниці статичний клас чи ні) можна не турбуватись про проблеми доступу при ініціалізації. Це правило діє для статичних полів, коли в коді декларується присвоєння значення змінної при оголошенні:

public class UsbKeyboard
{
    public static readonly UsbKeyboard Instance = new UsbKeyboard();
}

Щодо інших обмежень. В C# існують такі собі Extension Methods (http://msdn.microsoft.com/en-us/library/bb383977(v=vs.90).aspx). Дуже прикольна штука для розширення можливостей існуючих класів, код яких ми не можемо змінити, або змінювати не доречно. Такі методи можуть бути оголошенні лише в статичному класі.
Якщо виділити конкретну технологію, то скажу що в Silverlight не можна робити Binding на статичний клас. Для цього там в тому чи іншому вигляді використовується паттерн сінглтон.
Як би нам не хотілось, проте сінглтони та статичні класи будуть використовуватись в тому чи іншому випадку. Як їх створювати залежить від архітектури та розуміння девелопера як потрібно писати код і як не потрібно. Я раджу використовувати статичні класи для хелпер методів, які не зберігають ніякого стейту будь чого. Якщо в статичному класі потрібно використовувати доступ до сторонніх ресурсів, передавайте їх об’єкти в параметрах через інтерфейси (наприклад для доступу до сховища даних). Робіть сінглтони, коли потрібно зберігати якісь глобальні стейти, не змінні ресурси. Найкращими прикладами коли і навіщо створювати героїв теми є System.Math та System.Linq.Enumerable для статичного класу та HttpContext.Current для сінглтону.

Використані матеріали:











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

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