Наиболее распространенные примеры неправильного использования синглтон-класса - PullRequest
12 голосов
/ 25 сентября 2008

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

Ответы [ 11 ]

9 голосов
/ 25 сентября 2008

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

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

Типичный пример: «Это приложение имеет только одно соединение с базой данных, поэтому оно одноэлементное». - Плохая идея. Возможно, вы захотите иметь несколько соединений в будущем. Лучше создать пул соединений с базой данных и заполнить его только одним экземпляром. Действует как Singleton, но весь другой код будет иметь расширяемый код для доступа к пулу.

РЕДАКТИРОВАТЬ: Я понимаю, что теоретически вы можете расширить синглтон на несколько объектов. Тем не менее, не существует реального жизненного цикла (такого как объединение в пул / отмена), что означает, что нет реального права собственности на объекты, которые были розданы, то есть теперь мульти-синглтон должен быть без сохранения состояния, чтобы использоваться одновременно различными методами и потоками. 1009 *

6 голосов
/ 25 сентября 2008

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

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

3 голосов
/ 25 сентября 2008

Я знаю, что многие ответили "когда у вас их больше одного" и т. Д.

Поскольку первоначальный плакат требовал списка случаев, когда вы не должны использовать Singletons (а не основную причину), я добавлю:

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

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

2 голосов
/ 25 сентября 2008

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

2 голосов
/ 25 сентября 2008

Несколько лет назад я был виновен в большой (к счастью, с тех пор я выучил урок).

То, что случилось, - то, что я вошел в проект настольного приложения, который преобразовал в .Net от VB6, и был настоящим беспорядком. Такие вещи, как 40-страничные (печатные) функции и отсутствие реальной структуры классов. Я построил класс для инкапсуляции доступа к базе данных. Не настоящий уровень данных (пока), просто базовый класс, который может использовать настоящий уровень данных. Где-то у меня появилась яркая идея сделать этот класс синглтоном. Он работал нормально год или около того, а затем нам нужно было создать веб-интерфейс для приложения. Синглтон оказался огромным узким местом для базы данных, поскольку все веб-пользователи должны были использовать одно и то же соединение. Опять ... урок усвоен.

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

1 голос
/ 25 сентября 2008

Я пытаюсь иметь только один синглтон - инверсию объекта локатора управления / обслуживания.

IService service = IoC.GetImplementationOf<IService>();
1 голос
/ 25 сентября 2008

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

Посмотрите, как работает Dependency Injection. Он решает те же проблемы, но гораздо более полезным способом - на самом деле, вы обнаружите, что он применим ко многим другим частям вашего дизайна.

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

0 голосов
/ 26 сентября 2008

В случае соединения (например), имеет смысл, что вы не хотите делать само соединение одиночным, вам может потребоваться четыре соединения, или вам может потребоваться уничтожить и воссоздать соединение с несколькими раз.

Но почему бы вам не получить доступ к всем вашим соединениям через единый интерфейс (т. Е. Диспетчер соединений)?

0 голосов
/ 25 сентября 2008

Если в одной JVM запущено несколько приложений.

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

0 голосов
/ 25 сентября 2008

Иногда вы предполагаете, что будет только одна вещь, и тогда вы ошибаетесь.

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

// Its our database! We'll never need another
class Database
{
};

Но подожди! Ваш босс говорит, подключитесь к базе данных других парней. Допустим, вы хотите добавить phpbb на веб-сайт и хотели бы использовать его базу данных для интеграции некоторых его функций. Должны ли мы сделать новый синглтон или другой экземпляр базы данных? Большинство людей согласны с тем, что новый экземпляр того же класса предпочтительнее, дублирование кода отсутствует.

Вы бы предпочли

Database ourDb;
Database otherDb;

затем скопируйте базу данных и сделайте:

// Copy-pasted from our home-grown database.
class OtherGuysDatabase
{
};

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

...