Singleton не так прост


Когда я начинал изучать шаблоны проектирования первым я осилил Одиночка (англ. Singleton). Он мне показался простым и понятным. Так уж получилось, что я сейчас разрабатываю инспекцию для Idea которая проверяет корректность синглтонов, поэтому я погрузился в тему глубже и обнаружил что их использование связано со многими нюансами.

Так вот, этот шаблон наверное наиболее часто используется на практике и при чаще всего критикуется. Главным образом из-за того что он затрудняет юнит-тестирование и по сути является теми же глобальными переменными.

Singleton это практически обход проблемы что нельзя создать сразу сложный объект не описав его класс.

Например, в одном из самых навороченных языков программирования Scala для него ввели специальную конструкцию object которой заменили статические поля и методы. В JavaScript, как и во всех прототипных языках, мы вообще по сути сразу создаём такие объекты.

Так что они имеют точно такое же право на жизнь как например интерфейсы, которые частично можно заменить полностью абстрактными классами. Но это уже на правах холивара.

Если вы решили бороться с сиглтонами, то к вашим услугам в Idea есть специальная инспекция которая определяет синглтоны как проблемы. Также в Google написали инструмент Singleton Detector который находит синглетоны и помогает от них избавлятся.

Критику можно почитать на вики проекта и в энциклопедии хороших практик Cunningham & Cunningham.

Беглый осмотр матчасти

Я сделал небольшой Copy & Paste конспект из нагугленого матана, главным образом из этих статей:

Пример 1. Простейший, идиоматический синглтон

public class Singleton  {
    private static final Singleton instance = new Singleton();
 
    // Private constructor prevents instantiation from other classes
    private Singleton() {
    }
 
    public static Singleton getInstance() {
        return instance ;
    }
}

Именно такой и генерируется в Idea.

Пример 2. С отложенной инициализацией

В первом примере экземпляр класса instance статический, и создаётся сразу при загрузке класса. За всё время работы програмы он может так и не пригодится, поэтому делают ленивую инициализацию.

public class Singleton  {
    private static Singleton instance = null;
 
    // Private constructor prevents instantiation from other classes
    private Singleton() {
    }
 
    /**
     * Метод возвращает экземпляр SomeObject, при этом он
     * создаёт его, если тот ещё не существует
     */
    public static Singleton getInstance() {
        if (instance == null)
             instance = new Singleton();
        return instance;
    }
}

Проверка, создан уже экземпляр или нет очень дешёвая, поэтому по возможности старайтесь делать отложенную инициализацию.

Пример 3. Потокобезопасный

Несколько потоков могут одновременно дёргнуть getInstance() и он создаст несколько экземпляров класса. Чтобы этого избежать создание экземпляра делают в блоке synchronized

public class Singleton {
private static Singleton instance = null;

// Private constructor prevents instantiation from other classes
private Singleton() {
}

/**
* Метод возвращает экземпляр SomeObject, при этом он
* создаёт его, если тот ещё не существует
*/
public static synchronized Singleton getInstance() {
if (instance == null)
instance = new Singleton();
return instance;
}
}
Продолжение следует…

UPD Продолжения не следует, тему раскрыли на хабре здесь и здесь

Реклама

One comment

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s