07-09-2023
Одиночка | |
Singleton | |
Тип: |
порождающий |
---|---|
Описан в Design Patterns |
Да |
Одиночка (англ. Singleton) в программировании — порождающий шаблон проектирования.
Гарантирует, что у класса есть только один экземпляр, и предоставляет к нему глобальную точку доступа. Существенно то, что можно пользоваться именно экземпляром класса, так как при этом во многих случаях становится доступной более широкая функциональность. Например, к описанным компонентам класса можно обращаться через интерфейс, если такая возможность поддерживается языком.
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; } }
Остерегайтесь, это антипаттерн!
public class Singleton { protected Singleton() {} private static class SingletonHolder { public static Singleton instance = new Singleton(); } public static Singleton getInstance() { return SingletonHolder.instance; } }
public enum SingletonEnum { INSTANCE; public void someMethod() { *** } public void anotherMethod() { *** } }
class Singleton(type): def __init__(cls, name, bases, dict): super(Singleton, cls).__init__(name, bases, dict) cls.instance = None def __call__(cls,*args,**kw): if cls.instance is None: cls.instance = super(Singleton, cls).__call__(*args, **kw) return cls.instance >>> class MyClass(object): ... __metaclass__ = Singleton ... >>> a = MyClass() >>> a.attr = 12 >>> b = MyClass() >>> b.attr 12 >>> a is b True
Возможная реализация на C++ (известная как синглтон Майерса), где одиночка представляет собой статический локальный объект. Важным моментом является то, что конструктор класса объявлен как private, что позволяет предотвратить создание экземпляров класса за пределами его реализации. Отметим также, что приведенный пример потоко-небезопасен, для работы с классом из нескольких потоков нужно защитить переменную theSingleInstance
от одновременного доступа, например, с помощью мьютекса или критической секции.
class OnlyOne { public: static OnlyOne* Instance() { if(theSingleInstance==NULL) theSingleInstance=new OnlyOne; return theSingleInstance; } private: static OnlyOne* theSingleInstance; OnlyOne(){}; }; OnlyOne* OnlyOne::theSingleInstance=NULL;
/// generic Singleton<T> (потокобезопасный с использованием generic-класса и с отложенной инициализацией) /// <typeparam name="T">Singleton class</typeparam> public class Singleton<T> where T : class { /// Защищенный конструктор по умолчанию необходим для того, чтобы /// предотвратить создание экземпляра класса Singleton protected Singleton() { } /// Фабрика используется для отложенной инициализации экземпляра класса private sealed class SingletonCreator<S> where S : class { //Используется Reflection для создания экземпляра класса без публичного конструктора private static readonly S instance = (S) typeof(S).GetConstructor( BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[0], new ParameterModifier[0]).Invoke(null); public static S CreatorInstance { get { return instance; } } } public static T Instance { get { return SingletonCreator<T>.CreatorInstance; } } } /// Использование Singleton public class TestClass : Singleton<TestClass> { private 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 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; } } //usage $test = &Singleton::getInstance(); ?>
<?php class Singleton { protected static $instance; // object instance /** * Защищаем от создания через new Singleton * * @return Singleton */ private function __construct() { /* ... */ } /** * Защищаем от создания через клонирование * * @return Singleton */ private function __clone() { /* ... */ } /** * Возвращает единственный экземпляр класса * * @return Singleton */ public static function getInstance() { if ( is_null(self::$instance) ) { self::$instance = new self; } return self::$instance; } public function doAction() { /* ... */ } } //usage Singleton::getInstance()->doAction(); ?>
В языке Delphi вплоть до недавних версий было невозможно скрыть стандартный конструктор Create, кроме того, отсутствовали поля класса (что, впрочем, не вызывало неудобств при правильном разбиении программного кода на модули).
unit SingletonUnit; interface type TSingleton = class private constructor ActualCreate; public constructor Create; class function GetInstance: TSingleton; end; implementation var Singleton: TSingleton; constructor TSingleton.ActualCreate; begin inherited; end; constructor TSingleton.Create; begin raise Exception.Create('Attempt to create an instance of TSingleton') end; class function TSingleton.GetInstance: TSingleton; begin if Singleton = nil then Singleton := TSingleton.ActualCreate; Result := Singleton; end; end.
Singleton := Object clone Singleton clone := Singleton
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
(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))
Module Program Sub Main() Dim T1 As Singleton = Singleton.getInstance T1.Value = 1000 Dim T2 As Singleton = Singleton.getInstance Console.WriteLine(T2.Value) Console.Read() End Sub End Module Public Class Singleton Public Value As Integer 'Не разрешаем конструктор Protected Sub New() End Sub Private NotInheritable Class SingletonCreator Private Shared ReadOnly m_instance As New Singleton() Public Shared ReadOnly Property Instance() As Singleton Get Return m_instance End Get End Property End Class Public Shared ReadOnly Property getInstance() As Singleton Get Return SingletonCreator.Instance End Get End Property End Class
package Singleton; use strict; my $singleton; sub new { my $class = shift(); return $singleton ||= bless(sub {1}, $class); } 1;
package { public class Singleton { private static var _instance:Singleton = null; public function Singleton() { } static public function get instance():Singleton { if (_instance == null) _instance = new Singleton(); return _instance; } } }
В данном примере используется механизм замыканий, предотвращающий возможную модификацию приватных членов псевдокласса.
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, но не в его прототипе
Наиболее короткий вариант. Стоит отметить, что статические свойства "класса" затрутся.
function Singleton() { // Код конструктора var single = this; Singleton = function() { return single }; // Переопределяем конструктор } console.assert( new Singleton === new Singleton );
Генерик вариант.
var Singleton = new function() { var instance; return function() { if ( !instance ) { instance = this; } else return instance; // Код конструктора }; }; console.assert( new Singleton === new Singleton );
Singleton.h
@interface Singleton : NSObject { } + (Singleton *)sharedInstance; @end
Singleton.m
@implementation Singleton static Singleton *_sharedInstance = nil; static void singleton_remover() { if (_sharedInstance) { [_sharedInstance release]; } } + (Singleton *)sharedInstance { if (!_sharedInstance) { _sharedInstance = [[Singleton alloc] init]; // release instance at exit atexit(singleton_remover); } return _sharedInstance; } @end
Это заготовка статьи о компьютерных языках. Вы можете помочь проекту, исправив и дополнив её. |
Одиночка (шаблон проектирования).