Singleton: Как это должно использоваться

Как будто вы пытаетесь получить доступ к объекту, который является null. Рассмотрим ниже пример:

TypeA objA;

. В это время вы только что объявили этот объект, но не инициализировали или не инициализировали. И всякий раз, когда вы пытаетесь получить доступ к каким-либо свойствам или методам в нем, он будет генерировать NullPointerException, что имеет смысл.

См. Также этот пример:

String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
285
задан 14 revs, 6 users 70% 23 May 2017 в 01:54
поделиться

18 ответов

Все Вы неправы. Считайте вопрос. Ответ:

Использование Singleton, если:

  • у Вас должен быть один и только один объект типа в системе

, не используют Singleton если:

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

, Как создать лучший одиночный элемент:

  • , Чем меньший, тем лучше. Я - минималист
  • , Удостоверяются, что это ориентировано на многопотоковое исполнение
  • , Удостоверяются, что это никогда не не пустое
  • , Удостоверяются, что это создается только однажды
  • Ленивый или системная инициализация? До Ваших требований
  • Иногда ОС или JVM создают одиночные элементы для Вас (например, в Java каждое определение класса является одиночным элементом)
  • , Обеспечивают деструктор или так или иначе выясняют, как расположить ресурсы
  • Использование мало памяти
168
ответ дан Maxim Srour 23 November 2019 в 01:50
поделиться

Я думаю, что это большая часть устойчивой версии для C#:

using System;
using System.Collections;
using System.Threading;

namespace DoFactory.GangOfFour.Singleton.RealWorld
{

  // MainApp test application

  class MainApp
  {
    static void Main()
    {
      LoadBalancer b1 = LoadBalancer.GetLoadBalancer();
      LoadBalancer b2 = LoadBalancer.GetLoadBalancer();
      LoadBalancer b3 = LoadBalancer.GetLoadBalancer();
      LoadBalancer b4 = LoadBalancer.GetLoadBalancer();

      // Same instance?
      if (b1 == b2 && b2 == b3 && b3 == b4)
      {
        Console.WriteLine("Same instance\n");
      }

      // All are the same instance -- use b1 arbitrarily
      // Load balance 15 server requests
      for (int i = 0; i < 15; i++)
      {
        Console.WriteLine(b1.Server);
      }

      // Wait for user
      Console.Read();    
    }
  }

  // "Singleton"

  class LoadBalancer
  {
    private static LoadBalancer instance;
    private ArrayList servers = new ArrayList();

    private Random random = new Random();

    // Lock synchronization object
    private static object syncLock = new object();

    // Constructor (protected)
    protected LoadBalancer()
    {
      // List of available servers
      servers.Add("ServerI");
      servers.Add("ServerII");
      servers.Add("ServerIII");
      servers.Add("ServerIV");
      servers.Add("ServerV");
    }

    public static LoadBalancer GetLoadBalancer()
    {
      // Support multithreaded applications through
      // 'Double checked locking' pattern which (once
      // the instance exists) avoids locking each
      // time the method is invoked
      if (instance == null)
      {
        lock (syncLock)
        {
          if (instance == null)
          {
            instance = new LoadBalancer();
          }
        }
      }

      return instance;
    }

    // Simple, but effective random load balancer

    public string Server
    {
      get
      {
        int r = random.Next(servers.Count);
        return servers[r].ToString();
      }
    }
  }
}

Вот оптимизированная.NET версия :

using System;
using System.Collections;

namespace DoFactory.GangOfFour.Singleton.NETOptimized
{

  // MainApp test application

  class MainApp
  {

    static void Main()
    {
      LoadBalancer b1 = LoadBalancer.GetLoadBalancer();
      LoadBalancer b2 = LoadBalancer.GetLoadBalancer();
      LoadBalancer b3 = LoadBalancer.GetLoadBalancer();
      LoadBalancer b4 = LoadBalancer.GetLoadBalancer();

      // Confirm these are the same instance
      if (b1 == b2 && b2 == b3 && b3 == b4)
      {
        Console.WriteLine("Same instance\n");
      }

      // All are the same instance -- use b1 arbitrarily
      // Load balance 15 requests for a server
      for (int i = 0; i < 15; i++)
      {
        Console.WriteLine(b1.Server);
      }

      // Wait for user
      Console.Read();    
    }
  }

  // Singleton

  sealed class LoadBalancer
  {
    // Static members are lazily initialized.
    // .NET guarantees thread safety for static initialization
    private static readonly LoadBalancer instance =
      new LoadBalancer();

    private ArrayList servers = new ArrayList();
    private Random random = new Random();

    // Note: constructor is private.
    private LoadBalancer()
    {
      // List of available servers
      servers.Add("ServerI");
      servers.Add("ServerII");
      servers.Add("ServerIII");
      servers.Add("ServerIV");
      servers.Add("ServerV");
    }

    public static LoadBalancer GetLoadBalancer()
    {
      return instance;
    }

    // Simple, but effective load balancer
    public string Server
    {
      get
      {
        int r = random.Next(servers.Count);
        return servers[r].ToString();
      }
    }
  }
}

можно найти этот шаблон в dotfactory.com .

0
ответ дан artur02 23 November 2019 в 01:50
поделиться

В настольных приложениях (я знаю, только нас, динозавры больше пишут их!) они важны для получения относительно неизменных глобальных параметров настройки приложения - пользовательский язык, путь к справочным файлам, пользовательские настройки и т.д., которые иначе имели бы к propogate в каждый класс и каждое диалоговое окно.

Редактирование - конечно, они должны быть только для чтения!

-1
ответ дан Martin Beckett 23 November 2019 в 01:50
поделиться

Антииспользование:

Одна основная проблема с чрезмерным одноэлементным использованием состоит в том, что шаблон предотвращает легкое расширение и свопинг альтернативных реализаций. Имя класса трудно кодируется везде, где одиночный элемент используется.

0
ответ дан Adam Franco 23 November 2019 в 01:50
поделиться

Я использую Одиночные элементы в качестве теста интервью.

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

1
ответ дан Matt Cruikshank 23 November 2019 в 01:50
поделиться

Но когда мне нужно что-то как Singleton, я часто заканчиваю тем, что использовал Счетчик Schwarz для инстанцирования ее.

2
ответ дан Matt Cruikshank 23 November 2019 в 01:50
поделиться

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

поэтому даже примеры регистраторов или пулов потоков недопустимы и должны быть заменены Стратегиями.

3
ответ дан ZebZiggle 23 November 2019 в 01:50
поделиться

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

, Если бы Вы сделали этот каждый раз, производительность была бы очень ухудшена. Используя его в одиночном элементе, Вы получаете тот удар однажды, и затем все последующие вызовы не должны делать этого.

3
ответ дан Brian 23 November 2019 в 01:50
поделиться

Первый пример не ориентирован на многопотоковое исполнение - если два потока называют getInstance одновременно, который статичный будет ЛАВАШЕМ. Некоторая форма взаимного исключения помогла бы.

5
ответ дан Rob 23 November 2019 в 01:50
поделиться

современный Дизайн C++ Alexandrescu имеет ориентированный на многопотоковое исполнение, наследуемый универсальный одиночный элемент.

Для моей 2p-ценности, я думаю, что важно определить время жизни для Ваших одиночных элементов (когда абсолютно необходимо использовать их). Я обычно не позволяю помехам get(), функция инстанцирует чего-либо, и установки отпуска и разрушения к некоторому специализированному разделу главного приложения. Это помогает выделить зависимости между одиночными элементами - но, как подчеркнуто выше, лучше просто избегать их, если это возможно.

6
ответ дан Toby Speight 23 November 2019 в 01:50
поделиться

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

Java в особенности использует одиночные элементы в качестве замены для глобальных переменных, так как все должно содержаться в классе. Самыми близкими это приходит к глобальным переменным, являются общедоступные статические переменные, которые могут использоваться, как будто они были глобальны с import static

, C++ действительно имеет глобальные переменные, но порядок, в котором вызываются конструкторы глобальных переменных класса, не определен. По сути, одиночный элемент позволяет Вам задержать создание глобальной переменной до первого раза, когда переменная необходима.

Языки, такие как Python и Ruby используют одиночные элементы очень мало, потому что можно использовать глобальные переменные в модуле вместо этого.

Поэтому, когда хорошо/плохо использовать одиночный элемент? В значительной степени точно, когда было бы хорошо/плохо использовать глобальную переменную.

12
ответ дан Eli Courtwright 23 November 2019 в 01:50
поделиться

Одна вещь с шаблонами: не делают вывод . У них есть все случаи, когда они полезны, и когда они перестали работать.

Singleton может быть противной, когда Вы имеете к тест код. Вы обычно застреваете с одним экземпляром класса и можете выбрать между открытием двери в конструкторе или некотором методе для сброса состояния и так далее.

Другая проблема состоит в том, что Singleton на самом деле является не чем иным как глобальная переменная скрытый. Когда у Вас есть слишком много глобального общего состояния по Вашей программе, вещи имеют тенденцию возвращаться, все мы знаем это.

Это может сделать зависимость, отслеживающая тяжелее. Когда все зависит от Вашей Singleton, более трудно изменить его, разделить к два, и т.д. Вы обычно застреваете с ним. Это также препятствует гибкости. Исследуйте [приблизительно 118] Внедрение зависимости платформа, чтобы попытаться облегчить эту проблему.

27
ответ дан Paweł Hajdan 23 November 2019 в 01:50
поделиться

Проблемой с одиночными элементами не является их реализация. Это - это, они соединяют два различных понятия, ни одно из которых не очевидно желательно.

1) Одиночные элементы предоставляют глобальный механизм доступа объекту. Хотя они могли бы быть незначительно более ориентированными на многопотоковое исполнение или незначительно более надежными на языках без четко определенного порядка инициализации, это использование является все еще моральным эквивалентом глобальной переменной. Это - глобальная переменная, наряженная в некотором неловком синтаксисе (нечто:: get_instance () вместо g_foo, говорят), но это служит той же самой цели (отдельный объект, доступный через всю программу), и имеет те же самые недостатки.

2) Одиночные элементы предотвращают несколько инстанцирований класса. Это редко, IME, что этот вид функции должен испечься в класс. Это обычно - намного больше контекстной вещи; много вещей, которые рассматриваются как one-and-only-one, действительно просто happens-to-be-only-one. IMO более соответствующее решение состоит в том, чтобы просто создать только один экземпляр - пока Вы не понимаете необходимость больше чем в одном экземпляре.

36
ответ дан DrPizza 23 November 2019 в 01:50
поделиться
  • Как правильно реализовать синглтон

Есть одна проблема, о которой я никогда не упоминал, с которой я столкнулся на предыдущей работе. У нас были синглтоны C ++, которые были разделены между DLL, и обычная механика обеспечения того, чтобы один экземпляр класса просто не работал. Проблема в том, что каждая DLL получает свой собственный набор статических переменных вместе с EXE. Если ваша функция get_instance является встроенной или является частью статической библиотеки, каждая DLL будет иметь свою собственную копию «singleton».

Решение состоит в том, чтобы убедиться, что одноэлементный код определен только в одной DLL или EXE, или создайте одноэлементный менеджер с этими свойствами для разделения экземпляров.

6
ответ дан 23 November 2019 в 01:50
поделиться

Большинство людей используют синглтоны, когда пытаются заставить себя чувствовать себя лучше при использовании глобальной переменной. Существуют законные применения, но в большинстве случаев, когда люди используют их, тот факт, что может быть только один экземпляр, является тривиальным фактом по сравнению с тем фактом, что он доступен во всем мире.

3
ответ дан 23 November 2019 в 01:50
поделиться

Синглтоны дают вам возможность комбинировать две плохие черты в одном классе. Это неправильно почти во всех отношениях.

Синглтон дает вам:

  1. Глобальный доступ к объекту и
  2. Гарантия того, что не может быть создано более одного объекта этого типа

Номер один прост. Глобалы вообще плохие. Мы никогда не должны делать объекты глобально доступными, если нам действительно это не нужно.

Второй может показаться, что это имеет смысл, но давайте подумаем об этом. Когда в последний раз вы ** случайно * создавали новый объект вместо ссылки на существующий? Поскольку это тег C ++, давайте использовать пример из этого языка. Вы часто случайно пишете

std::ostream os;
os << "hello world\n";

Когда вы намеревались написать

std::cout << "hello world\n";

Конечно, нет. Нам не нужна защита от этой ошибки, потому что такого рода ошибки просто не происходят. Если это так, то правильным ответом будет пойти домой и поспать 12-20 часов и надеяться, что вы почувствуете себя лучше.

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

Ограничение «возможен только один экземпляр» на самом деле не защищает нас от возможных ошибок. Но это действительно делает наш код очень сложным для рефакторинга и сопровождения. Потому что довольно часто мы узнаем позже , что нам нужно более одного экземпляра. У нас есть более одной базы данных, у нас есть более одного объекта конфигурации, нам нужно несколько регистраторов. Наши модульные тесты могут захотеть создавать и воссоздавать эти объекты каждый тест, чтобы взять общий пример.

Таким образом, синглтон должен использоваться тогда и только тогда, когда нам нужно оба свойства, которые он предлагает : Если нам нужен глобальный доступ (что редко, поскольку глобальные списки обычно не приветствуются) и нам нужно , чтобы предотвратить создание кого-либо более одного экземпляра класса (что звучит для меня как проблема дизайна). Единственная причина, по которой я это вижу, заключается в том, что создание двух экземпляров повредит нашему состоянию приложения - возможно, потому, что класс содержит несколько статических членов или аналогичную глупость. В этом случае очевидный ответ - исправить этот класс. Это не должно Это зависит от того, чтобы быть единственным экземпляром.

Если вам нужен глобальный доступ к объекту, сделайте его глобальным, как std :: cout . Но не ограничивайте количество экземпляров, которые могут быть созданы.

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

Если вам нужны обе черты, то 1) сделайте его синглтоном и 2) дайте мне знать, для чего вам это нужно, потому что мне трудно представить такой случай.

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

Если вам нужны обе черты, то 1) сделайте его синглтоном и 2) дайте мне знать, для чего вам это нужно, потому что мне трудно представить такой случай.

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

Если вам нужны обе черты, то 1) сделайте его синглтоном и 2) дайте мне знать, для чего вам это нужно, потому что мне трудно представить такой случай.

71
ответ дан 23 November 2019 в 01:50
поделиться

Поскольку синглтон позволяет создать только один экземпляр, он эффективно контролирует репликацию экземпляра. например, вам не потребуется несколько экземпляров поиска - например, карта поиска Морзе, таким образом, можно обернуть его в одноэлементный класс. И то, что у вас есть единственный экземпляр класса, не означает, что вы также ограничены количеством ссылок на этот экземпляр. Вы можете ставить вызовы в очередь (чтобы избежать проблем с потоками) экземпляру и вносить необходимые изменения. Да, общая форма синглтона является глобально общедоступной, вы, конечно, можете изменить дизайн, чтобы создать синглтон с более ограниченным доступом. Я не уставал от этого раньше, но я уверен, что это возможно. вы, конечно, можете изменить дизайн, чтобы создать синглтон с более ограниченным доступом. Я не уставал от этого раньше, но я уверен, что это возможно. вы, конечно, можете изменить дизайн, чтобы создать синглтон с более ограниченным доступом. Я не уставал от этого раньше, но я уверен, что это возможно. И всем, кто прокомментировал, говоря, что шаблон синглтона является крайне злым, вы должны знать следующее: да, это зло, если вы не используете его должным образом или в пределах его эффективной функциональности и предсказуемого поведения: не ОБОБЩАЙТЕ ОБОБЩЕНИЯ.

3
ответ дан 23 November 2019 в 01:50
поделиться

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

Некоторые полезные аспекты синглтонов. :

  1. ленивое или предварительное создание экземпляра
  2. удобно для объекта, который требует настройки и / или состояния

Однако вам не нужно использовать синглтон, чтобы получить эти преимущества. Вы можете написать обычный объект, который выполняет эту работу, а затем предоставить людям доступ к нему через фабрику (отдельный объект). Фабрика может беспокоиться только о создании одного экземпляра, его повторном использовании и т. Д., Если это необходимо. Кроме того, если вы программируете для интерфейса, а не для конкретного класса, фабрика может использовать стратегии, то есть вы можете включать и выключать различные реализации интерфейса.

Наконец,

5
ответ дан 23 November 2019 в 01:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: