Хороший случай для синглетонов?

У меня есть приложение, в котором есть несколько классов, используемых для хранения настроек всего приложения (расположения ресурсов, пользовательских настроек и т. Д.). Прямо сейчас эти классы просто полны статических полей и методов, но я никогда не создаю их экземпляры.

Кто-то предложил мне сделать их синглтонами, в чём дело за / против?

7
задан stacker 17 August 2010 в 06:04
поделиться

10 ответов

Эффективная Java говорит:

Singletons typically represent some system component that is intrinsically 
unique, such as a video display or file system.

Итак, если ваш компонент гарантирует единственный экземпляр во всем приложении и у него есть какое-то состояние , имеет смысл сделать его singleton

В вашем случае настройки приложения - хороший кандидат на singleton.

С другой стороны, у класса могут быть только статические методы, если вы хотите сгруппировать вместе определенные функции, такие как служебные классы, примерами в jdk являются java.util.Arrays java.util.Collections. У них есть несколько связанных методов, которые работают с массивами или коллекциями

9
ответ дан 6 December 2019 в 08:40
поделиться

Синглтон предоставит вам ссылку на объект, которую вы можете использовать во всем приложении ... вы будете использовать синглтон, если вам нужны объекты и / или полиморфизм ...

1
ответ дан 6 December 2019 в 08:40
поделиться

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

Я считаю, что в основном я использую синглтоны в классе, который имеет статические методы, которые, возможно, подготовив среду, создают экземпляр самого себя. Используя частные конструкторы и переопределив Object.clone () , чтобы выбросить CloneNotSupportedException , никакие другие классы не могут создать его новый экземпляр или, если они когда-либо передали его экземпляр, они не могут его клонировать.

Думаю, я бы сказал, что если настройки вашего приложения являются частью класса, который никогда не создается, неуместно говорить «Это должно / не должно быть одноэлементным».

0
ответ дан 6 December 2019 в 08:40
поделиться

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

Самое простое, что вы можете сделать, - это статическая переменная:

public class Globals{
   public static final int ACONSTANT=1;

Это нормально и гарантирует, что у вас будет только одна, и у вас не будет проблем с созданием экземпляров. Основным недостатком, конечно же, является то, что запекать ваши данные часто неудобно. Также возникает проблема с загрузкой, если, например, ваша строка фактически построена, скажем, путем создания чего-то из внешнего ресурса (есть также Попался с примитивами - если ваш статический финал представляет собой int, скажем, классы, которые зависят от него, компилируют его встроенным образом, это означает, что перекомпиляция ваших констант не может заменить константы в приложении - например, учитывая общедоступный класс B {int i = Globals.ACONSTANT;} изменение Globals.ACONSTANT и перекомпиляция только Globals оставит Bi по-прежнему = 1.)

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

Итак, в основном: Статика

  • Хорошо: легко кодировать, код ясен и прост
  • Плохо: не настраивается - вам нужно перекомпилировать, чтобы изменить свои значения, может не работать, если ваши глобальные данные требуют сложной инициализации

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

0
ответ дан 6 December 2019 в 08:40
поделиться

Я считаю, что шаблон Singleton является наиболее неправильно применяемым шаблоном проектирования. За ~ 12 лет разработки программного обеспечения я бы сказал, что видел 5 подходящих примеров.

Я работал над проектом, в котором у нас была служба системного мониторинга, которая смоделировала нашу систему с помощью класса System (не путать со встроенным в Java классом System ), который содержал список из Подсистем , каждая со списком из Компонентов и так далее. Разработчик сделал Систему синглтоном. Я спросил: "Почему это синглтон?" Ответ: «Ну, есть только одна система». «Я знаю, но почему вы сделали его синглтоном? Не могли бы вы просто создать один экземпляр нормального класса и передать его классам, которым он нужен?» «Было проще просто вызвать getInstance () повсюду, вместо того, чтобы передавать его». «О ...»

Этот пример типичен: синглтоны часто используются неправильно как удобный способ доступа к единственному экземпляру класса, а не для принудительного применения уникального экземпляра по техническим причинам. Но за это приходится платить. Когда класс зависит от getInstance () , он навсегда привязан к реализации Singleton. Это делает его менее тестируемым, многоразовым и настраиваемым.Это нарушает основное правило, которому я следую, и которое, вероятно, имеет общее название в некоторых эссе о принципах дизайна: классы не должны знать, как создавать экземпляры своих зависимостей. Почему? Потому что он жестко объединяет классы. Когда класс вызывает конструктор, он привязывается к реализации. getInstance () ничем не отличается. Лучшая альтернатива - передать интерфейс в класс, и что-то еще может выполнить вызов конструктора / getInstance () / factory. Именно здесь на помощь приходят фреймворки внедрения зависимостей, такие как Spring, хотя они и не нужны (просто очень приятно иметь).

Итак, когда уместно использовать синглтон? В том редком случае, когда создание более одного экземпляра чего-либо буквально разрушит приложение. Я не говорю о создании экземпляров двух Земель в приложении солнечной системы - это просто ошибка. Я имею в виду, когда есть какое-то базовое оборудование или программный ресурс, который взорвет ваше приложение, если вы вызовете / выделите / создадите его более одного раза. Даже в этом случае классы, использующие синглтон, не должны знать, что это синглтон. Должен быть один и только один вызов getInstance () , который возвращает интерфейс, который затем передается конструкторам / установщикам классов, которые в нем нуждаются. Я предполагаю, что это можно сказать по-другому: вы должны использовать синглтон из-за его «единственности», а не из-за его «глобальной доступности».

Между прочим, в этом проекте я упоминал, где System была синглтоном ... Ну, System.getInstance () был замешан во всей базе кода, наряду с несколькими другими несоответствующими Синглтоны.Год спустя появились некоторые новые требования: «Мы развертываем нашу систему на нескольких сайтах и ​​хотим, чтобы служба мониторинга системы могла контролировать каждый экземпляр». Каждый экземпляр ... хммм ... getInstance () не поможет: -)

11
ответ дан 6 December 2019 в 08:40
поделиться

Я думаю, вам не нужно создавать класс signleton. просто сделайте этот конструктор класса закрытым. Как класс математики в java.

public final class Math {

    /**
     * Don't let anyone instantiate this class.
     */
    private Math() {}

//static fields and methods

}
0
ответ дан 6 December 2019 в 08:40
поделиться

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

В других случаях, если методы статичны, не будет никакой выгоды, как в классе javas Math, который имеет только статические члены.

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

0
ответ дан 6 December 2019 в 08:40
поделиться

Вы должны использовать синглтоны для модуляции.

Представьте себе следующие объекты в синглтоне:

Printer prt;
HTTPInfo httpInfo;
PageConfig pgCfg;
ConnectionPool cxPool;

Случай 1 . Представьте, если бы вы этого не сделали, а только один класс для хранения всех статических полей / методов. Тогда вам придется иметь дело с одним большим пулом статики.

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

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

Случай 3 Идентификатор ресурса.
Синглтоны позволяют легко масштабировать ресурсы. Допустим, теперь у вас есть единственная база данных, с которой нужно работать, и поэтому вы помещаете все ее настройки как статические в класс MyConnection. Что, если наступит время, когда вам потребуется подключиться к нескольким базам данных? Если бы вы закодировали информацию о соединении как одноэлементную, усовершенствование кода было бы намного проще.

Случай 4 Наследование.
Синглтон-классы позволяют расширять себя. Если у вас есть класс ресурсов, они могут использовать общий код. Допустим, у вас есть класс BasicPrinter, который можно создать как синглтон. Тогда у вас есть LaserPrinter, который расширяет BasicPrinter.

Если бы вы использовали статические средства, ваш код сломался бы, потому что вы не смогли бы получить доступ к BasicPrinter.isAlive как LaserPrinter.isAlive. Тогда ваш единственный фрагмент кода не сможет управлять различными типами принтеров, если вы не разместите избыточный код.

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

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

Случай 5 Избегайте информационной публичности. Так мало информации, которую нужно сделать глобально доступной, например, самые большие и самые маленькие целые числа. Почему нужно разрешить Printer.isAlive создавать трибуны? Только очень ограниченный набор информации должен быть допущен для создания трибуны.

Есть такая поговорка: «Думай глобально, действуй локально». Точно так же программист должен использовать синглтоны, чтобы мыслить глобально, но действовать локально.

0
ответ дан 6 December 2019 в 08:40
поделиться

Эффективная Java говорит:

Синглтоны обычно представляют собой некоторый системный компонент, который по своей сути уникальные, такие как видеодисплей или файловая система.

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

(Вышеупомянутое явно заимствовано из Naikus)

Во многих случаях описанная выше ситуация может быть обработана «служебным классом», в котором все методы статичны. Но иногда синглтон все же предпочтительнее.

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

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

0
ответ дан 6 December 2019 в 08:40
поделиться

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

Если должен быть один , а ровно один экземпляр объекта: используйте Singleton. Под этим я подразумеваю, должна ли программа ОСТАНОВИТЬСЯ, если есть более одного объекта. Хороший пример - если вы разрабатываете видеоигру, которая всегда поддерживает рендеринг только на одно устройство вывода. Попытка снова открыть то же устройство (позор вам за жесткое кодирование!) Будет запрещена. ИМХО такой случай часто означает, что вам вообще не следует использовать классы. Даже C позволяет тривиально инкапсулировать такую ​​проблему без сложности создания класса синглтона и при этом поддерживать элементы объектно-ориентированного программирования, которые применяются к синглтону.Когда вы застряли на таком языке, как Java / C #, вам придется работать с одноэлементным шаблоном, если только чисто статические члены не справятся с этим самостоятельно. Вы все еще можете смоделировать другой путь через них.

Если это просто случай взаимодействия объектов, вам, вероятно, следует подумать о более объектно-ориентированном подходе. Вот еще один пример: предположим, что код рендеринга наших игровых движков должен взаимодействовать с менеджерами ресурсов и ввода, чтобы он мог выполнять свою работу. Вы можете создать эти синглтоны и сделать что-то вроде ResourceManager.getInstance (). GetResource (name). Или вы можете создать класс приложения (например, GameEngine), в котором ResourceManager и InputManager являются закрытыми членами. Затем попросите GameEngine передать их по мере необходимости методам кода рендеринга. Например, r.render (resourcemanager) ;.

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

Против синглтонов - многие варианты использования синглтонов могут быть решены путем их инкапсуляции в родительский объект и передачи объекта-члена в методы других объектов-членов.

Иногда просто использовать глупую глобальную переменную - это правильно. Это похоже на использование GOTO или составного (и / или) условного оператора вместо того, чтобы писать один и тот же код обработки ошибок N раз с копированием и вставкой.


Кодируйте умнее, а не сложнее.

0
ответ дан 6 December 2019 в 08:40
поделиться
Другие вопросы по тегам:

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