Поиск…


замечания

Образец дизайна Singleton иногда рассматривается как « Анти-шаблон ». Это связано с тем, что у него есть некоторые проблемы. Вы должны сами решить, считаете ли вы целесообразным использовать его. Эта тема несколько раз обсуждалась в StackOverflow.

См .: http://stackoverflow.com/questions/137975/what-is-so-bad-about-singletons

Синглтон (C #)

Синглтоны используются для обеспечения создания только одного экземпляра объекта. Синглтон позволяет создавать только один экземпляр, который означает, что он контролирует его создание. Синглтон является одним из шаблонов дизайна Gang of Four и является шаблоном создания .

Нитевидный шаблон Singleton

public sealed class Singleton
{
    private static Singleton _instance;
    private static object _lock = new object();
 
    private Singleton()
    {
    }
 
    public static Singleton GetSingleton()
    {
        if (_instance == null)
        {
             CreateSingleton();
        }

        return _instance;
    }

    private static void CreateSingleton()
    {
        lock (_lock )
        {
            if (_instance == null)
            {
                 _instance = new Singleton();
            }
        }
    }
}

Jon Skeet обеспечивает следующую реализацию для ленивого, потокобезопасного синглтона:

public sealed class Singleton
{
    private static readonly Lazy<Singleton> lazy =
        new Lazy<Singleton>(() => new Singleton());
    
    public static Singleton Instance { get { return lazy.Value; } }

    private Singleton()
    {
    }
} 

Синглтон (Java)

Синглтоны в Java очень похожи на C #, поскольку оба языка ориентированы на объекты. Ниже приведен пример одноэлементного класса, в котором только одна версия объекта может быть жива во время жизни программы (предполагая, что программа работает в одном потоке)

public class SingletonExample {

    private SingletonExample() { }

    private static SingletonExample _instance;

    public static SingletonExample getInstance() {

        if (_instance == null) {
            _instance = new SingletonExample();
        }
        return _instance;
    }
}

Вот безопасная версия этой программы:

public class SingletonThreadSafeExample {

    private SingletonThreadSafeExample () { }

    private static volatile SingletonThreadSafeExample _instance;

    public static SingletonThreadSafeExample getInstance() {
        if (_instance == null) {
                createInstance();
        }
        return _instance;
    }

    private static void createInstance() {
        synchronized(SingletonThreadSafeExample.class) {
            if (_instance == null) {
                _instance = new SingletonThreadSafeExample();
            }
        }
    }
}

Java также имеет объект ThreadLocal , который создает один экземпляр объекта в потоке по потоку. Это может быть полезно в приложениях, где каждому потоку нужна собственная версия объекта

public class SingletonThreadLocalExample {

    private SingletonThreadLocalExample () { }

    private static ThreadLocal<SingletonThreadLocalExample> _instance = new ThreadLocal<SingletonThreadLocalExample>();

    public static SingletonThreadLocalExample getInstance() {
        if (_instance.get() == null) {
            _instance.set(new SingletonThreadLocalExample());
        }
        return _instance.get();
    }
}

Здесь также реализована реализация Singleton с enum (содержит только один элемент):

public enum SingletonEnum {
    INSTANCE;
    // fields, methods
}

Любая реализация класса Enum гарантирует, что существует только один экземпляр каждого его элемента.

Билл Пью Синглтон Узор

Bill Pugh Singleton Pattern - наиболее широко используемый подход для класса Singleton, поскольку он не требует синхронизации

public class SingletonExample {

    private SingletonExample(){}
    
    private static class SingletonHolder{
        private static final SingletonExample INSTANCE = new SingletonExample();
    }
    
    public static SingletonExample getInstance(){
        return SingletonHolder.INSTANCE;
    }
}

с использованием частного внутреннего статического класса держатель не загружается в память, пока кто-то не вызовет метод getInstance. Решение Bill Pugh является потокобезопасным, и для синхронизации не требуется.


В разделе « Синглтоны» в теге документации Java есть больше примеров синглтон Java.

Синглтон (C ++)

Согласно Wiki : в разработке программного обеспечения шаблон singleton представляет собой шаблон проектирования, который ограничивает создание экземпляра класса одним объектом.

Это необходимо для создания одного объекта для координации действий по всей системе.

class Singleton
{
    // Private constructor so it can not be arbitrarily created.
    Singleton()
    {}
    // Disable the copy and move
    Singleton(Singleton const&)            = delete;
    Singleton& operator=(Singleton const&) = delete;
  public:

    // Get the only instance
    static Singleton& instance()
    {
        // Use static member.
        // Lazily created on first call to instance in thread safe way (after C++ 11)
        // Guaranteed to be correctly destroyed on normal application exit.
        static Singleton _instance;

        // Return a reference to the static member.
        return _instance;
    }
};

Практический пример Lazy Singleton в java

Варианты использования в реальной жизни для шаблона Singleton;

Если вы разрабатываете клиент-серверное приложение, вам нужен единый вход ConnectionManager , который управляет жизненным циклом клиентских подключений.

Основные API в ConnectionManager:

registerConnection : Добавить новое соединение с существующим списком соединений

closeConnection : закрыть соединение либо из события, инициированного клиентом, либо сервером

broadcastMessage : несколько раз вам нужно отправить сообщение всем подписанным клиентским подключениям.

Я не предлагаю полную реализацию исходного кода, так как пример станет очень длинным. На высоком уровне код будет таким.

import java.util.*;
import java.net.*;

/* Lazy Singleton - Thread Safe Singleton without synchronization and volatile constructs */
final class  LazyConnectionManager {
    private Map<String,Connection> connections = new HashMap<String,Connection>();
    private LazyConnectionManager() {}
    public static LazyConnectionManager getInstance() {
        return LazyHolder.INSTANCE;
    }
    private static class LazyHolder {
        private static final LazyConnectionManager INSTANCE = new LazyConnectionManager();
    }

    /* Make sure that De-Serailzation does not create a new instance */
    private Object readResolve()  {
        return LazyHolder.INSTANCE;
    }
    public void registerConnection(Connection connection){
        /* Add new connection to list of existing connection */
        connections.put(connection.getConnectionId(),connection);
    }
    public void closeConnection(String connectionId){
        /* Close connection and remove from map */
        Connection connection = connections.get(connectionId);
        if ( connection != null) {
            connection.close();
            connections.remove(connectionId);
        }
    }
    public void broadcastMessage(String message){
        for (Map.Entry<String, Connection> entry : connections.entrySet()){
            entry.getValue().sendMessage(message);            
        }
    }    
}

Пример Тип сервера:

class Server implements Runnable{
    ServerSocket socket;
    int id;
    public Server(){
        new Thread(this).start();
    }
    public void run(){
        try{
            ServerSocket socket = new ServerSocket(4567);
            while(true){
                Socket clientSocket = socket.accept();
                ++id;
                Connection connection = new Connection(""+ id,clientSocket);
                LazyConnectionManager.getInstance().registerConnection(connection);    
                LazyConnectionManager.getInstance().broadcastMessage("Message pushed by server:");
            }
        }catch(Exception err){
            err.printStackTrace();
        }
    }
    
}

Другие практические примеры использования для Singletons:

  1. Управление глобальными ресурсами, такими как ThreadPool, ObjectPool, DatabaseConnectionPool и т. Д.
  2. Централизованные службы, такие как Logging данных приложений с различными уровнями журнала, такими как DEBUG,INFO,WARN,ERROR т. Д.
  3. Global RegistryService где различные сервисы регистрируются центральным компонентом при запуске. Этот глобальный сервис может действовать как Facade приложения

Пример C #: многопоточный синглтон

Статическая инициализация подходит для большинства ситуаций. Когда ваше приложение должно задерживать создание экземпляра, используйте конструктор не по умолчанию или выполняйте другие задачи до создания экземпляра и работайте в многопоточной среде, вам нужно другое решение. Однако существуют случаи, когда вы не можете полагаться на общую среду исполнения для обеспечения безопасности потоков, как в примере статической инициализации. В таких случаях вы должны использовать определенные языковые возможности, чтобы гарантировать, что только один экземпляр объекта создается в присутствии нескольких потоков. Одним из наиболее распространенных решений является использование идиомы Double-Check Locking [Lea99] для одновременного сохранения отдельных потоков от создания новых экземпляров синглтона.

Следующая реализация позволяет только одному потоку войти в критическую область, которую блокирует блок блокировки, когда еще один экземпляр Singleton еще не создан:

using System;

public sealed class Singleton {    
   private static volatile Singleton instance;    
   private static object syncRoot = new Object();

   private Singleton() {}

   public static Singleton Instance    {
      get 
      {
         if (instance == null) 
         {
            lock (syncRoot) 
            {
               if (instance == null) 
                  instance = new Singleton();
            }
         }

         return instance;
      }    
  } 
}

Такой подход гарантирует создание только одного экземпляра и только тогда, когда требуется экземпляр. Кроме того, переменная объявляется изменчивой, чтобы гарантировать, что присвоение переменной экземпляра завершается до того, как будет доступна доступ к переменной экземпляра. Наконец, этот подход использует экземпляр syncRoot для блокировки, а не для блокировки самого типа, чтобы избежать взаимоблокировок.

Этот метод двойной проверки блокировки решает проблемы параллелизма потоков, избегая при этом исключительной блокировки при каждом вызове метода свойств экземпляра. Он также позволяет задерживать создание экземпляра до тех пор, пока объект не будет первым. На практике приложение редко требует такого типа реализации. В большинстве случаев достаточно статического инициализационного подхода.

Ссылка: MSDN

Подтверждения

[Гамма95] Гамма, Шлем, Джонсон и Влиссидес. Шаблоны проектирования: элементы многоразового объектно-ориентированного программного обеспечения. Addison-Wesley, 1995.

[Lea99] Lea, Doug. Параллельное программирование на Java, второе издание. Addison-Wesley, 1999.

[Sells03] Продает, Крис. «Запечатанный сосет». Новости. Доступно по адресу: http://www.sellsbrothers.com/news/showTopic.aspx?ixTopic=411 .

Синглтон (PHP)

Пример от phptherightway.com

<?php
class Singleton
{
    /**
     * @var Singleton The reference to *Singleton* instance of this class
     */
    private static $instance;
    
    /**
     * Returns the *Singleton* instance of this class.
     *
     * @return Singleton The *Singleton* instance.
     */
    public static function getInstance()
    {
        if (null === static::$instance) {
            static::$instance = new static();
        }
        
        return static::$instance;
    }

    /**
     * Protected constructor to prevent creating a new instance of the
     * *Singleton* via the `new` operator from outside of this class.
     */
    protected function __construct()
    {
    }

    /**
     * Private clone method to prevent cloning of the instance of the
     * *Singleton* instance.
     *
     * @return void
     */
    private function __clone()
    {
    }

    /**
     * Private unserialize method to prevent unserializing of the *Singleton*
     * instance.
     *
     * @return void
     */
    private function __wakeup()
    {
    }
}

class SingletonChild extends Singleton
{
}

$obj = Singleton::getInstance();
var_dump($obj === Singleton::getInstance());             // bool(true)

$anotherObj = SingletonChild::getInstance();
var_dump($anotherObj === Singleton::getInstance());      // bool(false)

var_dump($anotherObj === SingletonChild::getInstance()); // bool(true)

Шаблон дизайна Singleton (в общем)

Примечание. Синглтон - это шаблон проектирования.
Но он также считался анти-шаблоном.

Следует использовать осторожно перед использованием синглтон. Как правило, лучшие альтернативы.

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

Проблемы с синглонами можно смягчить, используя их в сочетании с шаблонами создания; так что можно управлять начальным созданием синглтона.



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow