Одиночка (шаблон проектирования)
Одиночка, (англ. Singleton) — порождающий шаблон проектирования.
Цель
Гарантирует, что у класса есть только один экземпляр, и предоставляет к нему глобальную точку доступа. Существенно то, что можно пользоваться именно экземпляром класса, так как при этом во многих случаях становится доступной более широкая функциональность. Например, к описанным компонентам класса можно обращаться через интерфейс, если такая возможность поддерживается языком.
Плюсы
- контролируемый доступ к единственному экземпляру;
- уменьшение числа имён;
- допускает уточнение операций и представления;
- допускает переменное число экземпляров;
- большая гибкость, чем у операций класса.
Минусы
- Глобальные объекты могут быть вредны для объектного программирования, в некоторых случаях приводя к созданию немасштабируемого проекта.
Применение
- должен быть ровно один экземпляр некоторого класса, легко доступный всем клиентам;
- единственный экземпляр должен расширяться путем порождения подклассов, и клиентам нужно иметь возможность работать с расширенным экземпляром без модификации своего кода
Пример реализации
Пример Java 1.5: с отложенной инициализацией
<source lang="java"> 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;
}
} </source>
Пример Java 1.5: Class holder on JVM start initialization
<source lang="java"> public class Singleton {
protected Singleton() {}
private static class SingletonHolder {
public static Singleton instance = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.instance;
}
} </source>
Пример Java 1.5: Enum singleton
<source lang="java"> public enum SingletonEnum {
INSTANCE;
public void someMethod() {
***
}
public void anotherMethod() {
***
}
} </source>
Пример Python
<source lang="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
</source>
Пример C++
Возможная реализация на C++ (известная как синглтон Мейерса), где одиночка представляет собой статический локальный объект (важно: это решение не потоко-безопасно и приводится только для того, чтобы показать как устроен шаблон, а не для реального использования в крупномасштабных программных проектах. Кроме того, данная реализация не обеспечивает невозможность создать еще один экземпляр класса).
<source lang="cpp">
template<typename T> class Singleton
{
public:
static T& Instance()
{
static T theSingleInstance; // у класса T есть конструктор по умолчанию
return theSingleInstance;
}
};
class OnlyOne : public Singleton<OnlyOne>
{
//.. интерфейс класса
};
</source>
Пример C#
<source lang="csharp">
/// generic Singleton<T> (потокобезопасный с использованием generic-класса и с отложенной инициализацией)
/// <typeparam name="T">Singleton class</typeparam> public class Singleton<T> where T : class, new() {
/// Защищенный конструктор по умолчанию необходим для того, чтобы
/// предотвратить создание экземпляра класса Singleton
protected Singleton() { }
/// Фабрика используется для отложенной инициализации экземпляра класса private sealed class SingletonCreatorwhere 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";
}
}
</source>
Так же можно использовать стандартный вариант потокобезопасной реализации Singleton с отложенной инициализацией:
<source lang="csharp"> 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; }
}
} </source>
Пример PHP 4
<source lang="php"> <?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;
}
} ?> </source>
Пример PHP 5
<source lang="php">
<?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(); ?> </source>
Пример на Delphi
<source lang="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.
</source>
Пример на языке Io
<source lang="Io">
Singleton := Object clone Singleton clone := Singleton
</source>
Пример на языке Ruby
<source lang="Ruby"> class Singleton
def self.new
@instance ||= super
end
end </source>
В стандартную библиотеку (Ruby 1.8 и выше) входит модуль Singleton, что позволяет создавать синглтоны еще проще:
<source lang="Ruby"> require 'singleton' class Foo
include Singleton
end a = Foo.instance # Foo.new недоступен, для получения ссылки на (единственный)
# экземпляр класса Foo следует использовать метод Foo#instance
</source>
Пример на Common Lisp
<source lang="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))
</source>
Пример на Perl
<source lang="perl"> package Singleton;
use strict;
my $singleton;
sub new {
my $class = shift();
return $singleton ||= bless(sub {1}, $class);
}
1; </source>
Пример на ActionScript3
<source lang="actionscript"> 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 { }</source>
Пример на JavaScript с инкапсуляцией
В данном примере используется механизм замыканий, предотвращающий возможную модификацию приватных членов псевдокласса. <source lang="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' </source>
Без использования сокрытия переменных есть более простое решение, основанное на том, что функция Singleton является объектом. Минусом является возможность изменения св-ва instance вне класса: <source lang="javascript"> 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, но не в его прототипе </source>
См. также
Ссылки
- Паттерн Singleton (Одиночка) — пример использования шаблона (C++).
- Одиночка — простое описание с примером применения.
- Реализация синглтонов — пример для Delphi.
- Шаблон Singleton — пример для Java.
- [1] - The "Double-Checked Locking is Broken" Declaration in java
- Реализация синглтонов на Perl — пример для Perl.
- Singleton Considered Stupid — критика Паттерна Singleton
| порождающие шаблоны проектирования |
| абстрактная фабрика | строитель | фабричный метод | прототип | одиночка | отложенная инициализация |
| SQL | Это незавершённая статья о компьютерных языках. Вы можете помочь проекту, исправив и дополнив её. |
bg:Сек (шаблон) 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:单例模式
Если вам нравится SbUP.com Сайт, вы можете поддержать его - BTC: bc1qppjcl3c2cyjazy6lepmrv3fh6ke9mxs7zpfky0 , TRC20 и ещё....