Как будто вы пытаетесь получить доступ к объекту, который является null
. Рассмотрим ниже пример:
TypeA objA;
. В это время вы только что объявили этот объект, но не инициализировали или не инициализировали. И всякий раз, когда вы пытаетесь получить доступ к каким-либо свойствам или методам в нем, он будет генерировать NullPointerException
, что имеет смысл.
См. Также этот пример:
String a = null;
System.out.println(a.toString()); // NullPointerException will be thrown
Все Вы неправы. Считайте вопрос. Ответ:
Использование Singleton, если:
, не используют Singleton если:
, Как создать лучший одиночный элемент:
Я думаю, что это большая часть устойчивой версии для 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 .
В настольных приложениях (я знаю, только нас, динозавры больше пишут их!) они важны для получения относительно неизменных глобальных параметров настройки приложения - пользовательский язык, путь к справочным файлам, пользовательские настройки и т.д., которые иначе имели бы к propogate в каждый класс и каждое диалоговое окно.
Редактирование - конечно, они должны быть только для чтения!
Антииспользование:
Одна основная проблема с чрезмерным одноэлементным использованием состоит в том, что шаблон предотвращает легкое расширение и свопинг альтернативных реализаций. Имя класса трудно кодируется везде, где одиночный элемент используется.
Я использую Одиночные элементы в качестве теста интервью.
то, Когда я прошу, чтобы разработчик назвал некоторые шаблоны разработки, если все они могут назвать, является Singleton, они не наняты.
Но когда мне нужно что-то как Singleton, я часто заканчиваю тем, что использовал Счетчик Schwarz для инстанцирования ее.
Реальное крушение Одиночных элементов состоит в том, что они повреждают наследование. Вы не можете получить новый класс, чтобы дать Вам расширенную функциональность, если у Вас нет доступа к коду, где на Singleton ссылаются. Так, вне факта Singleton сделает Ваш код сильно связанным (закрепляемый Стратегической моделью... иначе Внедрение зависимости), это будет также препятствовать тому, чтобы Вы закрыли разделы кода от пересмотра (совместно использованные библиотеки).
поэтому даже примеры регистраторов или пулов потоков недопустимы и должны быть заменены Стратегиями.
Одиночные элементы удобны, когда у Вас есть много кода, выполняемого, когда Вы инициализируете и возражаете. Например, когда Вы использующий iBatis при установке персистентности возражаете, что она должна считать все конфигурации, проанализировать карты, удостоверьтесь, все исправляют и т.д. прежде, чем добраться до Вашего кода.
, Если бы Вы сделали этот каждый раз, производительность была бы очень ухудшена. Используя его в одиночном элементе, Вы получаете тот удар однажды, и затем все последующие вызовы не должны делать этого.
Первый пример не ориентирован на многопотоковое исполнение - если два потока называют getInstance одновременно, который статичный будет ЛАВАШЕМ. Некоторая форма взаимного исключения помогла бы.
современный Дизайн C++ Alexandrescu имеет ориентированный на многопотоковое исполнение, наследуемый универсальный одиночный элемент.
Для моей 2p-ценности, я думаю, что важно определить время жизни для Ваших одиночных элементов (когда абсолютно необходимо использовать их). Я обычно не позволяю помехам get()
, функция инстанцирует чего-либо, и установки отпуска и разрушения к некоторому специализированному разделу главного приложения. Это помогает выделить зависимости между одиночными элементами - но, как подчеркнуто выше, лучше просто избегать их, если это возможно.
Одиночные элементы в основном позволяют Вам иметь сложное глобальное состояние на языках, которые иначе мешают или невозможный иметь сложные глобальные переменные.
Java в особенности использует одиночные элементы в качестве замены для глобальных переменных, так как все должно содержаться в классе. Самыми близкими это приходит к глобальным переменным, являются общедоступные статические переменные, которые могут использоваться, как будто они были глобальны с import static
, C++ действительно имеет глобальные переменные, но порядок, в котором вызываются конструкторы глобальных переменных класса, не определен. По сути, одиночный элемент позволяет Вам задержать создание глобальной переменной до первого раза, когда переменная необходима.
Языки, такие как Python и Ruby используют одиночные элементы очень мало, потому что можно использовать глобальные переменные в модуле вместо этого.
Поэтому, когда хорошо/плохо использовать одиночный элемент? В значительной степени точно, когда было бы хорошо/плохо использовать глобальную переменную.
Одна вещь с шаблонами: не делают вывод . У них есть все случаи, когда они полезны, и когда они перестали работать.
Singleton может быть противной, когда Вы имеете к тест код. Вы обычно застреваете с одним экземпляром класса и можете выбрать между открытием двери в конструкторе или некотором методе для сброса состояния и так далее.
Другая проблема состоит в том, что Singleton на самом деле является не чем иным как глобальная переменная скрытый. Когда у Вас есть слишком много глобального общего состояния по Вашей программе, вещи имеют тенденцию возвращаться, все мы знаем это.
Это может сделать зависимость, отслеживающая тяжелее. Когда все зависит от Вашей Singleton, более трудно изменить его, разделить к два, и т.д. Вы обычно застреваете с ним. Это также препятствует гибкости. Исследуйте [приблизительно 118] Внедрение зависимости платформа, чтобы попытаться облегчить эту проблему.
Проблемой с одиночными элементами не является их реализация. Это - это, они соединяют два различных понятия, ни одно из которых не очевидно желательно.
1) Одиночные элементы предоставляют глобальный механизм доступа объекту. Хотя они могли бы быть незначительно более ориентированными на многопотоковое исполнение или незначительно более надежными на языках без четко определенного порядка инициализации, это использование является все еще моральным эквивалентом глобальной переменной. Это - глобальная переменная, наряженная в некотором неловком синтаксисе (нечто:: get_instance () вместо g_foo, говорят), но это служит той же самой цели (отдельный объект, доступный через всю программу), и имеет те же самые недостатки.
2) Одиночные элементы предотвращают несколько инстанцирований класса. Это редко, IME, что этот вид функции должен испечься в класс. Это обычно - намного больше контекстной вещи; много вещей, которые рассматриваются как one-and-only-one, действительно просто happens-to-be-only-one. IMO более соответствующее решение состоит в том, чтобы просто создать только один экземпляр - пока Вы не понимаете необходимость больше чем в одном экземпляре.
- Как правильно реализовать синглтон
Есть одна проблема, о которой я никогда не упоминал, с которой я столкнулся на предыдущей работе. У нас были синглтоны C ++, которые были разделены между DLL, и обычная механика обеспечения того, чтобы один экземпляр класса просто не работал. Проблема в том, что каждая DLL получает свой собственный набор статических переменных вместе с EXE. Если ваша функция get_instance является встроенной или является частью статической библиотеки, каждая DLL будет иметь свою собственную копию «singleton».
Решение состоит в том, чтобы убедиться, что одноэлементный код определен только в одной DLL или EXE, или создайте одноэлементный менеджер с этими свойствами для разделения экземпляров.
Большинство людей используют синглтоны, когда пытаются заставить себя чувствовать себя лучше при использовании глобальной переменной. Существуют законные применения, но в большинстве случаев, когда люди используют их, тот факт, что может быть только один экземпляр, является тривиальным фактом по сравнению с тем фактом, что он доступен во всем мире.
Синглтоны дают вам возможность комбинировать две плохие черты в одном классе. Это неправильно почти во всех отношениях.
Синглтон дает вам:
Номер один прост. Глобалы вообще плохие. Мы никогда не должны делать объекты глобально доступными, если нам действительно это не нужно.
Второй может показаться, что это имеет смысл, но давайте подумаем об этом. Когда в последний раз вы ** случайно * создавали новый объект вместо ссылки на существующий? Поскольку это тег C ++, давайте использовать пример из этого языка. Вы часто случайно пишете
std::ostream os;
os << "hello world\n";
Когда вы намеревались написать
std::cout << "hello world\n";
Конечно, нет. Нам не нужна защита от этой ошибки, потому что такого рода ошибки просто не происходят. Если это так, то правильным ответом будет пойти домой и поспать 12-20 часов и надеяться, что вы почувствуете себя лучше.
Если нужен только один объект, просто создайте один экземпляр. Если один объект должен быть глобально доступен, сделайте его глобальным. Но это не значит, что нельзя создавать другие экземпляры этого.
Ограничение «возможен только один экземпляр» на самом деле не защищает нас от возможных ошибок. Но это действительно делает наш код очень сложным для рефакторинга и сопровождения. Потому что довольно часто мы узнаем позже , что нам нужно более одного экземпляра. У нас есть более одной базы данных, у нас есть более одного объекта конфигурации, нам нужно несколько регистраторов. Наши модульные тесты могут захотеть создавать и воссоздавать эти объекты каждый тест, чтобы взять общий пример.
Таким образом, синглтон должен использоваться тогда и только тогда, когда нам нужно оба свойства, которые он предлагает : Если нам нужен глобальный доступ (что редко, поскольку глобальные списки обычно не приветствуются) и нам нужно , чтобы предотвратить создание кого-либо более одного экземпляра класса (что звучит для меня как проблема дизайна). Единственная причина, по которой я это вижу, заключается в том, что создание двух экземпляров повредит нашему состоянию приложения - возможно, потому, что класс содержит несколько статических членов или аналогичную глупость. В этом случае очевидный ответ - исправить этот класс. Это не должно Это зависит от того, чтобы быть единственным экземпляром.
Если вам нужен глобальный доступ к объекту, сделайте его глобальным, как std :: cout
. Но не ограничивайте количество экземпляров, которые могут быть созданы.
Если вам абсолютно необходимо положительно ограничить количество экземпляров класса только одним, и нет никакого способа, которым создание второго экземпляра когда-либо может быть обработано. безопасно, а затем применить это. Но не делайте его и глобально доступным.
Если вам нужны обе черты, то 1) сделайте его синглтоном и 2) дайте мне знать, для чего вам это нужно, потому что мне трудно представить такой случай.
безусловно, необходимо ограничить число экземпляров класса одним, и нет никакого способа, которым создание второго экземпляра когда-либо можно было бы безопасно обработать, а затем применить это. Но не делайте его и глобально доступным.Если вам нужны обе черты, то 1) сделайте его синглтоном и 2) дайте мне знать, для чего вам это нужно, потому что мне трудно представить такой случай.
безусловно, необходимо ограничить число экземпляров класса одним, и нет никакого способа, которым создание второго экземпляра когда-либо можно было бы безопасно обработать, а затем применить это. Но не делайте его и глобально доступным.Если вам нужны обе черты, то 1) сделайте его синглтоном и 2) дайте мне знать, для чего вам это нужно, потому что мне трудно представить такой случай.
Поскольку синглтон позволяет создать только один экземпляр, он эффективно контролирует репликацию экземпляра. например, вам не потребуется несколько экземпляров поиска - например, карта поиска Морзе, таким образом, можно обернуть его в одноэлементный класс. И то, что у вас есть единственный экземпляр класса, не означает, что вы также ограничены количеством ссылок на этот экземпляр. Вы можете ставить вызовы в очередь (чтобы избежать проблем с потоками) экземпляру и вносить необходимые изменения. Да, общая форма синглтона является глобально общедоступной, вы, конечно, можете изменить дизайн, чтобы создать синглтон с более ограниченным доступом. Я не уставал от этого раньше, но я уверен, что это возможно. вы, конечно, можете изменить дизайн, чтобы создать синглтон с более ограниченным доступом. Я не уставал от этого раньше, но я уверен, что это возможно. вы, конечно, можете изменить дизайн, чтобы создать синглтон с более ограниченным доступом. Я не уставал от этого раньше, но я уверен, что это возможно. И всем, кто прокомментировал, говоря, что шаблон синглтона является крайне злым, вы должны знать следующее: да, это зло, если вы не используете его должным образом или в пределах его эффективной функциональности и предсказуемого поведения: не ОБОБЩАЙТЕ ОБОБЩЕНИЯ.
Как отмечали другие, основные недостатки синглтонов включают невозможность их расширения и потерю возможности создавать более одного экземпляра, например, в целях тестирования.
Некоторые полезные аспекты синглтонов. :
Однако вам не нужно использовать синглтон, чтобы получить эти преимущества. Вы можете написать обычный объект, который выполняет эту работу, а затем предоставить людям доступ к нему через фабрику (отдельный объект). Фабрика может беспокоиться только о создании одного экземпляра, его повторном использовании и т. Д., Если это необходимо. Кроме того, если вы программируете для интерфейса, а не для конкретного класса, фабрика может использовать стратегии, то есть вы можете включать и выключать различные реализации интерфейса.
Наконец,