CodeLAB
на главную карта сайта обратная связь
каталог | задачи | паттерны | исходники | стат | форумы | ссылки
 гость
искать в
Главная >> Каталог задач >> Паттерны >> Порождающие >> Одиночка (Singleton)

<< назад
распечатать обсудить >>


Одиночка (Singleton)
реализации: java, количество: 4

Aвтор: this
Дата: 30.06.2007
Просмотров: 57034
Рейтинг: 0/0,0(0)
+
реализации(исходники) +добавить

Имя

«Паттерн
Singleton» codelab.ru источник оригинал codelab.ru

Одиночка – паттерн, порождающий объекты. источник codelab.ru оригинал codelab.ru

Условия, Задача, Назначение

Гарантирует, что у класса будет не более 1 созданного экземпляра, предоставляет к нему глобальную точку доступа (обычно статический метод).

Мотивация

Очень часто бывает нужно хранить в программе некоторый объект – уникальным, т.е. чтобы всегда, когда запрашивался объект данного класса – возвращался один и тот же экземпляр. Подумайте – о таком объекте как соединение с базой данных. Во всех частях приложения нужно обеспечить доступ к базе, при этом будет неразумным каждый раз в процессе одного и того же функционирования соединяться с базой данных заново (одна из самых трудоемких операций). Поэтому необходимо всегда когда запрашивается данный объект-соединение – возвращать уже существующий один и тот же экземпляр. codelab.ru оригинал источник codelab.ru

Как показывает опыт, в каждом более-менее большом приложении целесообразно иметь немало таких объектов: в системе может быть много принтеров, но возможен лишь один спулер; должны быть только одна файловая система и единственный оконный менеджер; в цифровом фильтре может находиться только один аналого-цифровой преобразователь (АЦП); бухгалтерская система обслуживает только одну компанию и т.д. codelab.ru источник codelab.ru оригинал
Как гарантировать, что у класса есть единственный экземпляр и что этот экземпляр легко доступен? Глобальная переменная дает доступ к объекту, но не запрещает инстанцировать класс в нескольких экземплярах. codelab.ru источник оригинал codelab.ru

Более удачное решение - сам класс контролирует то, что у него есть только один экземпляр, может запретить создание дополнительных экземпляров, перехватывая запросы на создание новых объектов, и он же способен предоставить доступ к своему экземпляру. Это и есть назначение паттерна одиночка. источник оригинал codelab.ru codelab.ru

Признаки применения, использования паттерна Одиночка (Singleton)

Если: источник codelab.ru оригинал codelab.ru
  1. Должен быть ровно один экземпляр некоторого класса, легко доступный всем клиентам codelab.ru codelab.ru источник оригинал
  2. Единственный экземпляр должен расширяться путем порождения подклассов, и клиентам нужно иметь возможность работать с расширенным экземпляром без модификации своего кода. оригинал источник codelab.ru codelab.ru

Решение

источник codelab.ru codelab.ru оригинал

оригинал источник codelab.ru codelab.ru

Участники паттерна Одиночка (Singleton)

codelab.ru источник оригинал codelab.ru

  1. Singleton - одиночка.
    Определяет операцию получения экземпляра (назовем ее Instance) - статический метод, который позволяет клиентам получать доступ к единственному экземпляру. Может нести ответственность за создание собственного уникального экземпляра. оригинал codelab.ru codelab.ru источник

Схема использования паттерна Одиночка (Singleton)

Клиенты получают доступ к экземпляру класса Singleton только через его операцию Instance. Таким образом, когда нужно создать, получить объект этого класса – клиент не инстанцирует его напрямую, а вызывает эту операцию Instance(статический метод) – и получает объект. источник codelab.ru codelab.ru оригинал

Вопросы, касающиеся реализации паттерна Одиночка (Singleton)

При реализации паттерна одиночка (singleton) необходимо рассмотреть следующие вопросы: источник codelab.ru оригинал codelab.ru
  1. Гарантирование единственного экземпляра.
    Паттерн одиночка устроен так, что тот единственный экземпляр, который имеется у класса, - самый обычный, но больше одного экземпляра создать не удастся. Чаще всего для этого прячут операцию, создающую экземпляры (защищенный или закрытый конструктор), за операцией класса (то есть за статической функцией-членом или методом класса), которая гарантирует создание не более одного экземпляра. Данная операция имеет доступ к переменной, где хранится уникальный экземпляр, и гарантирует инициализацию переменной этим экземпляром перед возвратом ее клиенту. При таком подходе можно не сомневаться, что одиночка будет создан и инициализирован перед первым использованием. оригинал codelab.ru codelab.ru источник
  2. Порождение подклассов Singleton. Основной вопрос не столько в том, как определить подкласс, а в том, как сделать, чтобы клиенты могли использовать только его единственный экземпляр, никак не создав других экземпляров. По существу, переменная, ссылающаяся на экземпляр одиночки, должна инициализироваться вместе с экземпляром подкласса. Простейший способ добиться этого - определить одиночку, которого нужно инстанцировать в операции Instance() класса Singleton.
    Другой способ выбора подкласса Singleton - вынести реализацию операции Instance из родительского класса и поместить ее в подкласс, т.е. разрешить переопределение этой операции. Это позволит программисту задать класс одиночки на этапе компиляции, но от клиента одиночка будет по-прежнему скрыт.
    Такой подход фиксирует выбор класса одиночки на этапе компиляции, затрудняя тем самым его подмену во время выполнения. Применение условных операторов для выбора подкласса увеличивает гибкость решения, но все равно множество возможных классов Singleton остается жестко «зашитым» в код. В общем случае ни тот, ни другой подход не обеспечивают достаточной гибкости.
    Искомой гибкости можно добиться за счет использования реестра одиночек. Вместо того чтобы задавать множество возможных классов Singleton в операции Instance(), одиночки могут регистрировать себя по имени в некотором всем известном реестре. Реестр сопоставляет одиночкам строковые имена (ключи). Когда операции Instance() нужен некоторый одиночка, она запрашивает его у реестра по имени. Начинается поиск указанного одиночки, и, если он существует, реестр возвращает его. Такой подход освобождает Instance от необходимости «знать» все возможные классы или экземпляры Singleton. Нужен лишь единый для всех классов Singleton интерфейс операций с реестром, api реестра т.е.:
     RegSingleton, api реестра [java]  ссылка
    1. package singleton;
    2.  
    3. import java.util.HashMap;
    4. import java.util.Map;
    5.  
    6. public class RegSingleton {
    7. private static RegSingleton _instance;
    8. private static Map _registry = new HashMap();
    9.  
    10. protected RegSingleton() { }
    11.  
    12. public static void Register(String name, RegSingleton obj) {
    13. _registry.put(name, obj);
    14. }
    15.  
    16. public static RegSingleton Instance() {
    17. if (_instance == null) {
    18. // User define this name in system property file
    19. // before program starts
    20. String name = System.getProperty("patterns.book.singletonName");
    21. _instance = RegSingleton.Lookup(name);
    22. }
    23. return _instance;
    24. }
    25.  
    26. protected static RegSingleton Lookup(String name) {
    27. return (RegSingleton) _registry.get(name);
    28. }
    29. }

    Операция Register регистрирует экземпляр класса RegSingleton (или его подклассов) под указанным именем. Чтобы не усложнять реестр, мы будем хранить в нем список объектов в виде пар «ключ-значение» (хеш-таблица). Каждый ключ (имя) отображается на один объект «одиночка». Операция Lookup ищет одиночку по ключу (имени), например – из данных property-файла.
    Но в какой момент подклассы RegSingleton (SingletonSub например) будут регистрировать себя? Одна из возможностей – конструктор, но, разумеется, конструктор не будет вызван, пока кто-то не инстанцирует класс, но ведь это та самая проблема, которую паттерн одиночка и пытается разрешить! Существуют некоторые обходные пути: в Java, например, это можно решить, задействовав статический блок инициализации, который просто лишь вызовет конструктор, создавая объект и ни к чему его не привязывая (метод Register его затем сам привяжет к регистру!):
     SingletonSub, через стат-инициализатор [java]  ссылка
    1. package singleton;
    2.  
    3. public class SingletonSub extends RegSingleton {
    4. // It's the only time and place when
    5. // its constructor invokes
    6. static {
    7. new SingletonSub();
    8. }
    9.  
    10. protected SingletonSub() {
    11. // put this subclass in common register with
    12. // this class name
    13. RegSingleton.Register(this.getClass().getName(), this);
    14. }
    15.  
    16. }
    Теперь класс RegSingleton не отвечает за создание одиночки. Его основной обязанностью становится обеспечение доступа к объекту-одиночке из любой части системы. источник codelab.ru оригинал codelab.ru

Результаты

Достоинства паттерна одиночка (Singleton): codelab.ru источник оригинал codelab.ru
  1. Контролируемый доступ к единственному экземпляру.
    Поскольку класс Singleton инкапсулирует свой единственный экземпляр, он полностью контролирует то, как и когда клиенты получают доступ к нему codelab.ru источник оригинал codelab.ru
  2. Уменьшение числа имен.
    Паттерн одиночка - шаг вперед по сравнению с глобальными переменными. Он позволяет избежать засорения пространства имен глобальными переменными, в которых хранятся уникальные экземпляры. codelab.ru codelab.ru оригинал источник
  3. Допускает уточнение операций и представления.
    От класса Singleton можно порождать подклассы, а приложение легко сконфигурировать экземпляром расширенного класса. Можно параметризировать приложение экземпляром того класса, который необходим во время выполнения. codelab.ru codelab.ru оригинал источник
  4. Допускает переменное число экземпляров.
    Очень важное достигнутое преимущество. Паттерн позволяет вам легко изменить свое решение и разрешить появление более одного экземпляра класса Singleton. Вы можете применять один и тот же подход для управления числом экземпляров, используемых в приложении. Изменить нужно будет лишь операцию, дающую доступ к экземпляру класса Singleton. Фактически, дается возможность контролировать количество инстанцированных экземпляров класса, фигурирующих где бы то ни было в приложении. codelab.ru оригинал codelab.ru источник
  5. Большая гибкость, чем у операций класса.
    Еще один способ реализовать функциональность одиночки - использовать операции класса, то есть статические члены. Но это препятствует изменению дизайна, если потребуется разрешить наличие нескольких экземпляров класса. Кроме того, статические члены не полиморфны, так что их нельзя будет переопределять в подклассах. codelab.ru codelab.ru оригинал источник

Пример

Предположим, что у нас есть имеется некоторая абстрактная фабрика SomeFactory. Абстрагируемся от продуктов фабрики, от логики ее работы и т.д. – здесь это совершенно не принципиально. источник codelab.ru оригинал codelab.ru
Существенно то, что приложению нужен лишь один экземпляр фабрики лабиринтов, и он должен быть доступен в любом коде, производящем любой из продуктов. Тут-то паттерн одиночка и приходит на помощь. Сделав фабрику SomeFactory одиночкой, мы сможем обеспечить глобальную доступность объекта, представляющего фабрику. источник оригинал codelab.ru codelab.ru

Нужно также сделать конструктор защищенным, чтобы предотвратить случайное инстанцирование, в результате которого будет создан лишний экземпляр: SomeFactory. codelab.ru оригинал codelab.ru источник

Теперь рассмотрим случай, что у нашей фабрики существуют подклассы: WiseFactory и QuickFactory. Конкретный подкласс фабрики, использующийся в приложении – определяется системными настройками. Все что нам нужно сделать – это добавить в операцию instance() все того же класса SomeFactory код выбора конкретной фабрики в зависимости от значения этого системного свойства – и конечно обеспечить подклассы фабрики защищенным конструктором (не то появится возможность напрямую инстанцировать фабрики, минуя все наши запреты): SomeFactory. codelab.ru источник codelab.ru оригинал

Отметим, что операцию Instance() нужно модифицировать при определении каждого нового подкласса SomeFactory. В данном приложении это, может быть, и не проблема, но для абстрактных фабрик, определенных в каркасе, такой подход трудно назвать приемлемым. источник codelab.ru оригинал codelab.ru

Одно из решений - воспользоваться принципом реестра, описанным ранее. Может помочь и динамическое связывание, тогда приложению не нужно будет загружать все неиспользуемые подклассы. источник codelab.ru оригинал codelab.ru

  codelab.ru оригинал источник codelab.ru

Известные применения паттерна Одиночка (Singleton)

Примером паттерна одиночка в Smalltalk-80 является множество изменений кода, представленное классом ChangeSet. Более тонкий пример – это отношение между классами и их метаклассами. Метаклассом называется класс класса, каждый метакласс существует в единственном экземпляре. У метакласса нет имени (разве что косвенное, определяемое экземпляром), но он контролирует свой уникальный экземпляр, и создать второй обычно не разрешается. codelab.ru codelab.ru оригинал источник

В библиотеке Interviews для создания пользовательских интерфейсов - паттерн одиночка применяется для доступа к единственным экземплярам классов Session (сессия) и WidgetKit (набор виджетов). Классом Session определяется главный цикл распределения событий в приложении. Он хранит пользовательские настройки стиля и управляет подключением к одному или нескольким физическим дисплеям. WidgetKit - это абстрактная фабрика для определения внешнего облика интерфейсных виджетов. Операция WidgetKit: instance () определяет конкретный инстанцируемый подкласс WidgetKit на основе переменной среды, которую устанавливает Session. Аналогичная операция в классе Session «выясняет», поддерживаются ли монохромные или цветные дисплеи, и соответственно конфигурирует одиночку Session. оригинал источник codelab.ru codelab.ru

Родственные паттерны

Паттерн одиночка (Singleton) целесообразно применять вместе со многими паттернами, например, такими так: абстрактная фабрика, строитель, прототип. оригинал codelab.ru источник codelab.ru



оригинал codelab.ru codelab.ru источник

  codelab.ru оригинал источник codelab.ru



Реализации: java(4)   +добавить реализацию

1) SomeFactory.java, code #433[автор:this]
2) SomeFactory.java, модификация, code #434[автор:this]
3) WiseFactory.java, code #435[автор:this]
4) QuickFactory.java, code #436[автор:this]


<< назад наверх
распечатать обсудить >>

 
каталог | задачи | паттерны | исходники | стат | форумы | карта сайта | контакты | ссылки 
© 2000-2017 CodeLAB Group
  Все права защищены
Страница сгенерирована за 0.028114 секунд
Количество запросов к БД: 14, gzip: 17.1kb/78.4kb(79%)