Одиночка (шаблон проектирования)
Материал из Seo Wiki - Поисковая Оптимизация и Программирование
Одиночка, (англ. Singleton) — порождающий шаблон проектирования.
[править] Цель
Гарантирует, что у класса есть только один экземпляр, и предоставляет к нему глобальную точку доступа. Существенно то, что можно пользоваться именно экземпляром класса, так как при этом во многих случаях становится доступной более широкая функциональность. Например, к описанным компонентам класса можно обращаться через интерфейс, если такая возможность поддерживается языком.
[править] Плюсы
- контролируемый доступ к единственному экземпляру;
- уменьшение числа имён;
- допускает уточнение операций и представления;
- допускает переменное число экземпляров;
- большая гибкость, чем у операций класса.
[править] Минусы
- Глобальные объекты могут быть вредны для объектного программирования, в некоторых случаях приводя к созданию немасштабируемого проекта.
[править] Применение
- должен быть ровно один экземпляр некоторого класса, легко доступный всем клиентам;
- единственный экземпляр должен расширяться путем порождения подклассов, и клиентам нужно иметь возможность работать с расширенным экземпляром без модификации своего кода
[править] Пример реализации
[править] Пример Java 1.5: с отложенной инициализацией
class Singleton { private volatile static Singleton instance; private Singleton() {} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
[править] Пример Java 1.5: Class holder on JVM start initialization
public class Singleton { protected Singleton() {} private static class SingletonHolder { public static Singleton instance = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.instance; } }
[править] Пример Java 1.5: Enum singleton
public enum SingletonEnum { INSTANCE; public void someMethod() { *** } public void anotherMethod() { *** } }
[править] Пример Python
>>> class Singleton(object): obj = None # Атрибут для хранения единственного экземпляра def __new__(cls,*dt,**mp): # класса Singleton. if cls.obj is None: # Если он еще не создан, то cls.obj = object.__new__(cls,*dt,**mp) # вызовем __new__ родительского класса return cls.obj # вернем синглтон ... >>> obj = Singleton() >>> obj.attr = 12 >>> new_obj = Singleton() >>> new_obj.attr 12 >>> new_obj is obj # new_obj и obj - это один и тот же объект True
[править] Пример C++
Возможная реализация на C++ (известная как синглтон Мейерса), где одиночка представляет собой статический локальный объект (важно: это решение не потоко-безопасно и приводится только для того, чтобы показать как устроен шаблон, а не для реального использования в крупномасштабных программных проектах. Кроме того, данная реализация не обеспечивает невозможность создать еще один экземпляр класса).
template<typename T> class Singleton { public: static T& Instance() { static T theSingleInstance; // у класса T есть конструктор по умолчанию return theSingleInstance; } }; class OnlyOne : public Singleton<OnlyOne> { //.. интерфейс класса };
[править] Пример C#
/// generic Singleton<T> (потокобезопасный с использованием generic-класса и с отложенной инициализацией) /// <typeparam name="T">Singleton class</typeparam> public class Singleton<T> where T : class, new() { /// Защищенный конструктор по умолчанию необходим для того, чтобы /// предотвратить создание экземпляра класса Singleton protected Singleton() { } /// Фабрика используется для отложенной инициализации экземпляра класса private sealed class SingletonCreator<S> where S : class, new() { private static readonly S instance = new S(); public static S CreatorInstance { get { return instance; } } } public static T Instance { get { return SingletonCreator<T>.CreatorInstance; } } } /// Использование Singleton public class TestClass : Singleton<TestClass> { public string TestProc() { return "Hello World"; } }
Так же можно использовать стандартный вариант потокобезопасной реализации Singleton с отложенной инициализацией:
public class Singleton { protected Singleton() { } private sealed class SingletonCreator { private static readonly Singleton instance = new Singleton(); public static Singleton Instance { get { return instance; } } } public static Singleton Instance { get { return SingletonCreator.Instance; } } }
[править] Пример PHP 4
<?php class Singleton { function Singleton( $directCall = true ) { if ( $directCall ) { trigger_error("Нельзя использовать конструктор для создания класса Singleton. Используйте статический метод getInstance ()",E_USER_ERROR); } //TODO: Добавьте основной код конструктора здесь } function &getInstance() { static $instance; if ( !is_object( $instance ) ) { $instance = new Singleton( false ); } return $instance; } } ?>
[править] Пример PHP 5
<?php class Singleton { // object instance private static $instance; private function __construct() {} private function __clone() {} public static function getInstance() { if (self::$instance === null) { self::$instance = new self; } return self::$instance; } public function doAction() { ... } } //usage Singleton::getInstance()->doAction(); ?>
[править] Пример на Delphi
unit Unit1; interface type TSingleton = class strict private constructor Create; class var FInstance: TSingleton; public class function GetInstance: TSingleton; end; implementation constructor TSingleton.Create; begin inherited; end; class function TSingleton.GetInstance: TSingleton; begin if FInstance = nil then begin FInstance := TSingleton.Create(); end; Result := FInstance; end; end.
[править] Пример на языке Io
Singleton := Object clone Singleton clone := Singleton
[править] Пример на языке Ruby
class Singleton def self.new @instance ||= super end end
В стандартную библиотеку (Ruby 1.8 и выше) входит модуль Singleton, что позволяет создавать синглтоны еще проще:
require 'singleton' class Foo include Singleton end a = Foo.instance # Foo.new недоступен, для получения ссылки на (единственный) # экземпляр класса Foo следует использовать метод Foo#instance
[править] Пример на Common Lisp
(defclass singleton-class () ;;метакласс, реализующий механизм синглтона ((instance :initform nil))) (defmethod validate-superclass ((class singleton-class) (superclass standard-class)) t) ;;Разрешаем наследование классов-синглтонов от обычных классов (defmethod validate-superclass ((class singleton-class) (superclass singleton-class)) t) ;;Разрешаем наследование классов-синглтонов от других классов-синглтонов (defmethod validate-superclass ((class standard-class) (superclass singleton-class)) nil) ;;Запрещаем наследование обычных классов от синглтонов (defmethod make-instance ((class singleton-class) &key) (with-slots (instance) class (or instance (setf instance (call-next-method))))) (defclass my-singleton-class () () (:metaclass singleton-class))
[править] Пример на Perl
package Singleton; use strict; my $singleton; sub new { my $class = shift(); return $singleton ||= bless(sub {1}, $class); } 1;
[править] Пример на ActionScript3
package { class Singleton { private static var instance:Singleton; public static function getInstance() : Singleton { if (instance == null) { instance = new Singleton(new Singletoniser()); } return instance; } public function Singleton(singletoniser : Singletoniser) { if (singletoniser == null) { throw new Error("Singleton is a singleton class, use getInstance() instead."); } } } } class Singletoniser { }
[править] Пример на JavaScript с инкапсуляцией
В данном примере используется механизм замыканий, предотвращающий возможную модификацию приватных членов псевдокласса.
function Singleton() { var foo = 'bar'; //локальная переменная function instantiate() { //локальная функция this.fun = function() { //эта функция доступна извне alert(foo); } return this; } function SingletonInstance() { return instantiate(); } return new SingletonInstance(); } var object1 = Singleton(); //фактически получаем экземпляр SingletonInstance object1.fun(); //выведет 'bar' - это возможно благодаря замыканию var object2 = Singleton(); alert(object1===object2); //выведет 'true' - переменные ссылаются на один и тот же объект alert(Singleton.foo); //выведет 'undefined', т.к. локальная переменная недоступна alert(object1.foo); //выведет 'undefined'
Без использования сокрытия переменных есть более простое решение, основанное на том, что функция Singleton является объектом. Минусом является возможность изменения св-ва instance вне класса:
function Singleton() { if (!Singleton.instance) { Singleton.instance = this; } else { return Singleton.instance; // должен возвращаеться object } // код конструктора располагается после проверки } var object1 = new Singleton(); var object2 = new Singleton(); alert(object1===object2); // выведет 'true' - переменные ссылаются на один и тот же объект alert(object1.instance); // выведет 'undefined', т.к. instance имеется в контрукторе object1, но не в его прототипе
[править] См. также
[править] Ссылки
- Паттерн Singleton (Одиночка) — пример использования шаблона (C++).
- Одиночка — простое описание с примером применения.
- Реализация синглтонов — пример для Delphi.
- Шаблон Singleton — пример для Java.
- [1] - The "Double-Checked Locking is Broken" Declaration in java
- Реализация синглтонов на Perl — пример для Perl.
- Singleton Considered Stupid — критика Паттерна Singleton
| порождающие шаблоны проектирования |
| абстрактная фабрика | строитель | фабричный метод | прототип | одиночка | отложенная инициализация |
| Файл:Compu-lang-stub-by-Mercury.png | Это незавершённая статья о компьютерных языках. Вы можете помочь проекту, исправив и дополнив её. |
ca:Patró singleton cs:Singleton de:Singleton (Entwurfsmuster) en:Singleton pattern es:Singleton fr:Singleton (patron de conception) he:תבנית Singleton it:Singleton ja:Singleton パターン ko:싱글턴 패턴 ml:സിംഗള്ട്ടണ് പാറ്റേണ് nl:Singleton (informatica) pl:Singleton (wzorzec projektowy) pt:Singleton sv:Singleton th:ซิงเกิลตันแพตเทิร์น tr:Tekillik Kalıbı uk:Одинак (шаблон проектування) zh:单例模式