Шаблон программирования Singleton в Delphi.

Расскажу сегодня о singleton‘ах — так называемых «одиночках».

Суть singleton’а в том, что он гарантирует, что он существует лишь в единственном экземпляре, и предоставляет доступ в единственной точке кода.

Разберём не просто суть singleton’а, но и сделаем из него шаблон для наследования в производственных масштабах. :]

Грамотный подход к организации ООП программы, используя singleton’ы, зачастую даёт очень оптимальные результаты.

Поясню вкратце одну эволюционную цепочку в программировании, которая логически должна приводить к singleton’ам:

  • Допустим начинающий программист во всю и без опаски юзает глобальные переменные. Не жалуясь на всё это потому что вроде как это всё ловко и лишний раз о каких-то структурах думать не надо.
  • Конечно это работает с университетскими задачками, но не более того.
  • Начав писать норм прогу по размерам и дойдя до 3к-4к строк, кодер уже врубается, что дальше он уже не уедет на глобальных переменных, минимум от того что пространство имён он уже  забил.
  • Ладно думает, буду источать оптимальность! И начинает запихивать самые важные переменные в классы и структуры, а их в свою очередь в объединяющие модули. «Ох ты оказывается как легче стало обращаться к методам и свойствам классов, тут уже точно не ошибёшься!» — радуется он.
  • Ну вообщем такими-то потугами наконец прога в 4к строк закончена.

А т.к. замечена тенденция развития оптимизации в этом плане, то любой пытливый ум поинтересуется — «а что в этом является абсолютом развития?».

И тут ответы приводят к singleton’ам.

Но как я заметил про реализацию singleton’ов не многие знают.

Самый распространённый пример — в основном останавливаются на классах типа TSomeManager, объявляют в этом же модуле глобал экземпляр этого класса и создают его в initialization ну и уничтожают соответственно в finalization.

Рассмотрим достоинства singleton‘ов перед глобальными переменными:

  • Конфликты имён сводятся к минимуму;
  • Не отвлекаемся на инициализацию класса. Singleton — он всегда один и зачастую инициализация проходит автоматически;
  • Нет проблем с многопоточностью. (конечно не до такой степени, чтобы пренебрегать критическими секциями);
  • При изменениях логики программы у singleton’а придётся подправлять только интерфейс, а при глобальных переменных нужно отслеживать весь код по всей программе, который с ними связан.

Теперь рассмотрим и сравним варианты реализации паттернов синглтонов:

1. Нашёл вот такую статью. В которой предлагается применять шаблон внедряя его методы прямо в класс, который необходимо сделать одиночкой. Чесно гря это самый «негибкий» пример.

2. В википедии можно найти такой код:

Ну наконец-то видна структура по которой становится ясна логика. Видно что такой класс нельзя создать обычным методом через конструктор, можно только получить его ссылку через GetInstance, в котором он проверяет создан ли уже объект Singleton или нет.

В принципе моя реализация, которой я пользовался последнее время, почти такая же, только была чуть более заточена под наследование: метод Create был объявлен как Virtual; что позволяло в наследниках переопределять его, реализуя в нём операции какие были нужны при создании (например загрузку чего-либо).

3. Но совсем недавно я узрел самую удачную, на мой взгляд, реализацию паттерна синглтона — это реализация от Ins’а.

 

Эта реализация принципиально отличается от первых 2-х тем, что это подход наследования класса от шаблонного. Это безусловно посложнее чем первые 2, но и намного прозрачнее(гибче).

Первые же 2 реализации ближе к подходу реализации на классовых методах. Это самый примитивный случай — тут уникальность гарантируется компилятором. Понятно, что у классовых методов есть очевидные ограничения.

Данной реализацией я сейчас и пользуюсь. Как можно заметить тут уже получается не совсем одиночка, т.к. можно создать сколько необходимо экземпляров наследников (если такое потребуется конечно), но если обращаться к нему через GetInstance он остаётся одиночкой по всем правилам, при этом в листе объектов будет находиться всегда 1 объект.

Ну и напоследок я приложил маленький пример реализации, который поможет до конца разобраться в сути данного подхода. По легенде в примере унаследован класс для настроек программы.

Скачать исходники с примером реализации: sharedfiles_singleton_template_demo.