Шаблон синглтона - Singleton pattern
В программной инженерии , то шаблон одноточечно является шаблоном проектирования программного обеспечения , что ограничивает создание экземпляра в виде класса к одному «единым» , например. Это полезно, когда нужен ровно один объект для координации действий в системе.
Термин происходит от математической концепции синглтона .
Обзор
Одноэлементный шаблон проектирования - это один из двадцати трех хорошо известных шаблонов проектирования «Банда четырех», которые описывают, как решать повторяющиеся проблемы проектирования для разработки гибкого и многократно используемого объектно-ориентированного программного обеспечения с целью облегчения его реализации, изменения и т.д. тестировать и повторно использовать объекты.
Шаблон проектирования singleton решает проблемы, позволяя:
- Убедитесь, что у класса есть только один экземпляр
- Легко получить доступ к единственному экземпляру класса
- Управляйте его созданием
- Ограничить количество экземпляров
- Доступ к глобальной переменной
Шаблон проектирования singleton описывает, как решать такие проблемы:
- Скрыть конструкторы этого класса .
- Определите общедоступную статическую операцию (
getInstance()
), которая возвращает единственный экземпляр класса.
По сути, одноэлементный шаблон заставляет его отвечать за то, чтобы он был создан только один раз. Скрытый конструктор - объявленный private
или - protected
гарантирует, что класс никогда не может быть создан извне. Доступ к публичной статической операции можно получить, используя имя класса и имя операции, например Singleton.getInstance()
.
Общее использование
- Абстрактная фабрика , Фабричный метод , строитель и прототип модели могут использовать одиночка.
- Фасадные объекты часто бывают одиночными, потому что требуется только один фасадный объект.
- Государственные объекты часто бывают одиночными.
- Синглтоны часто предпочтительнее глобальных переменных, потому что:
- Они не загрязняют глобальное пространство имен (или, в языках с вложенными пространствами имен, содержащее их пространство имен) ненужными переменными.
- Они допускают отложенное выделение и инициализацию, тогда как глобальные переменные во многих языках всегда потребляют ресурсы.
Ведение журнала - классический пример синглтона.
Критика
Критики считают, что одноэлементный класс является анти-шаблоном, поскольку он часто используется в сценариях, где он бесполезен, потому что он часто вводит ненужные ограничения в ситуациях, когда одноэлементный класс не будет полезен, тем самым вводя глобальное состояние в приложение.
Более того, поскольку к синглтону можно получить доступ откуда угодно без использования каких-либо параметров, любые зависимости не будут сразу видны разработчикам. Следовательно, разработчикам необходимо знать «внутреннюю работу кода, чтобы правильно его использовать».
Синглтоны также нарушают принцип единственной ответственности , потому что они не только отвечают за обычную задачу одиночного объекта, но также должны гарантировать, что только один экземпляр создается; обратите внимание, что это основано на «классическом» определении синглтона, в котором он отвечает за обеспечение своей собственной уникальности, например, с помощью статического getInstance()
метода.
Другой недостаток состоит в том, что синглтоны сложно тестировать, потому что они несут глобальное состояние на протяжении всей программы. В частности, потому что для модульного тестирования требуются слабосвязанные классы, чтобы изолировать то, что тестируется. Кроме того, когда определенный класс взаимодействует с синглтоном, этот класс и синглтон становятся тесно связанными , что делает невозможным тестирование класса самостоятельно без тестирования синглтона.
Реализации
Реализации одноэлементного шаблона должны:
- Убедитесь, что когда-либо существует только один экземпляр класса singleton; а также
- Обеспечьте глобальный доступ к этому экземпляру.
Обычно это делают:
- Объявление всех конструкторов класса закрытыми ; а также
- Предоставление статического метода , возвращающего ссылку на экземпляр.
Экземпляр обычно хранится как частная статическая переменная ; экземпляр создается при инициализации переменной, в какой-то момент до первого вызова статического метода.
Джава
Реализация синглтона в Java :
public class Coin {
private static final int ADD_MORE_COIN = 10;
private int coin;
private static Coin instance = new Coin(); // eagerly loads the singleton
private Coin(){
// private to prevent anyone else from instantiating
}
public static Coin getInstance() {
return instance;
}
public int getCoin() {
return coin;
}
public void addMoreCoin() {
coin += ADD_MORE_COIN;
}
public void deductCoin() {
coin--;
}
}
public final class Singleton {
private static final Singleton INSTANCE = new Singleton();
private Singleton() {}
public static Singleton getInstance() {
return INSTANCE;
}
}
Ленивая инициализация
В одноэлементной реализации может использоваться отложенная инициализация , когда экземпляр создается при первом вызове статического метода. Если статический метод может быть вызван из нескольких потоков одновременно, может потребоваться принять меры для предотвращения состояний гонки, которые могут привести к созданию нескольких экземпляров. Ниже приводится потокобезопасная реализация с использованием отложенной инициализации с блокировкой с двойной проверкой , написанная на Java. Чтобы избежать накладных расходов на синхронизацию при сохранении ленивой инициализации с безопасностью потоков, предпочтительным подходом в Java является использование идиомы инициализации по требованию держателя .
public final class Singleton {
private static volatile Singleton instance = null;
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized(Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
Python
class Singleton:
__instance = None
def __new__(cls, *args):
if cls.__instance is None:
cls.__instance = object.__new__(cls, *args)
return cls.__instance
C ++
Начиная с C ++ 11 , инициализация статической локальной переменной является поточно-ориентированной и происходит после первого вызова. Это более безопасная альтернатива, чем статическая переменная пространства имен или класса.
class Singleton {
public:
static Singleton& GetInstance() {
// Allocate with `new` in case Singleton is not trivially destructible.
static Singleton* singleton = new Singleton();
return *singleton;
}
private:
Singleton() = default;
// Delete copy/move so extra instances can't be created/moved.
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
Singleton(Singleton&&) = delete;
Singleton& operator=(Singleton&&) = delete;
};
C #
Реализация синглтона на C # :
public sealed class Singleton
{
public static Singleton Instance { get; } = new Singleton();
private Singleton() { }
}
В C # вы также можете использовать статические классы для создания синглтонов, где сам класс является синглтоном.
public static class Singleton
{
public static MyOtherClass Instance { get; } = new MyOtherClass();
}
Единство
Синглтоны могут быть полезным инструментом при разработке с помощью Unity благодаря тому, как создаются экземпляры классов. Этот метод предпочтительнее скрытия конструктора , поскольку в Unity можно создать экземпляр объекта с помощью скрытого конструктора. Чтобы предотвратить перезапись экземпляра, необходимо выполнить проверку, чтобы убедиться, что экземпляр перезаписан null
. Если он не равен нулю, GameObject
сценарий , содержащий вредоносный сценарий, должен быть уничтожен.
Если другие компоненты зависят от синглтона, порядок выполнения скрипта должен быть изменен, чтобы гарантировать, что компонент, определяющий синглтон, будет выполнен первым.
class Singleton : MonoBehaviour
{
public static Singleton Instance { get; private set; }
private void Awake()
{
if (Instance != null && Instance != this) {
Destroy(this.gameObject);
} else {
Instance = this;
}
}
}
Обратите внимание, что также можно реализовать синглтон, удалив только скрипт-нарушитель, а не GameObject
сам его, вместо этого вызвав Destroy(this)
.
Дротик
Реализация синглтона в Dart :
class Singleton {
Singleton._();
static Singleton get instance => Singleton._();
}
PHP
Реализация синглтона в PHP :
class Singleton
{
private static $instance = null;
private function __construct() {}
public static function getInstance(): self
{
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
}
Котлин
Ключевое слово объекта Kotlin объявляет одноэлементный класс
object Coin {
private var coin: Int = 0
fun getCoin():Int {
return coin
}
fun addCoin() {
coin += 10
}
fun deductCoin() {
coin--
}
}
Паскаль
Поточно- реализация одноточечного в Pascal :
unit SingletonPattern;
interface
type
TTest = class sealed
strict private
FCreationTime: TDateTime;
public
constructor Create;
property CreationTime: TDateTime read FCreationTime;
end;
function GetInstance: TTest;
implementation
uses
SysUtils
, SyncObjs
;
var
FCriticalSection: TCriticalSection;
FInstance: TTest;
function GetInstance: TTest;
begin
FCriticalSection.Acquire;
try
if not Assigned(FInstance) then
FInstance := TTest.Create;
Result := FInstance;
finally
FCriticalSection.Release;
end;
end;
constructor TTest.Create;
begin
inherited Create;
FCreationTime := Now;
end;
initialization
FCriticalSection := TCriticalSection.Create;
finalization
FreeAndNil(FCriticalSection);
end.
Использование:
procedure TForm3.btnCreateInstanceClick(Sender: TObject);
var
i: integer;
begin
for i := 0 to 5 do
ShowMessage(DateTimeToStr(GetInstance.CreationTime));
end;
Смотрите также
- Идиома держателя инициализации по требованию
- Многотонный узор
- Шаблон проектирования программного обеспечения
использованная литература
внешние ссылки
- Полная статья « Объяснение паттерна Java Singleton »
- Четыре различных способа реализации синглтона в Java « Способы реализации синглтона в Java »
- Отрывок из книги: Реализация шаблона Singleton на C # от Джона Скита
- Синглтон в Центре разработчиков шаблонов и практик Microsoft
- Статья IBM Питера Хаггара " Двойная проверка блокировки и шаблон синглтона "
- Гири, Дэвид (25 апреля 2003 г.). «Как ориентироваться в обманчиво простом шаблоне Singleton» . Шаблоны проектирования Java. JavaWorld . Проверено 21 июля 2020 .
- Google Singleton Detector (анализирует байт-код Java для обнаружения синглтонов)