Дело не в том, что сами синглеты плохие, а в шаблоне GoF. Единственным действительным аргументом, который является действительным, является то, что шаблон проектирования GoF не подходит для тестирования, особенно если тесты выполняются параллельно.
Использование одного экземпляра класса является допустимой конструкцией, если в коде применяются следующие средства:
Убедитесь, что класс, который будет использоваться в качестве одиночного, реализует интерфейс. Это позволяет реализовать заглушки или макеты с использованием одного и того же интерфейса
Убедитесь, что Singleton является поточно-ориентированным. Это данность.
Синглтон должен быть простым по своей природе и не слишком сложным.
Во время выполнения приложения, в котором необходимо передать синглеты данному объекту, используйте фабрику классов, которая создает этот объект, и фабрика классов передает экземпляр синглтона нужному классу.
Во время тестирования и для обеспечения детерминированного поведения создайте одноэлементный класс в качестве отдельного экземпляра в качестве самого фактического класса или заглушки / макета, который реализует его поведение, и передайте его как есть классу, который требует его. Не используйте фактор класса, который создает тестируемый объект, который нуждается во синглтоне во время теста, так как он пройдет единственный глобальный экземпляр этого объекта, что противоречит цели.
Мы использовали Singletons в наших решениях с большим успехом, которые можно тестировать, обеспечивая детерминированное поведение в параллельных потоках тестовых прогонов.
Только что заметил этот вопрос.
Это одно из вариантов использования NaN, которое имеет в виду комитет IEEE 754 (я был членом комитета). Правила распространения NaN в арифметике делают это очень привлекательным, потому что, если у вас есть результат в результате длинной последовательности вычислений, включающих некоторые инициализированные данные, вы не ошибетесь, приняв его за действительный результат. Это также может значительно упростить отслеживание ваших вычислений, чтобы найти, где вы используете инициализированные данные.
Тем не менее, есть несколько подводных камней, которые находятся вне контроля комитета 754: как отмечали другие, не все оборудование поддерживает значения NaN на скорости, что может привести к снижению производительности. К счастью, нечасто выполняется много операций с инициализированными данными в условиях, критичных к производительности.
NaN - разумный выбор для предложения «без значения» (например, язык программирования D использует их для неинициализированных значений), но поскольку любые сравнения с их участием будут ложными, вы можете получить несколько сюрпризов:
if (result == DEFAULT_VALUE)
не будет работать должным образом, если DEFAULT_VALUE
равно NaN, как упоминал Джон.
Они также могут вызвать проблемы с проверкой диапазона если вы не будете осторожны. Рассмотрим функцию:
bool isOutsideRange(double x, double minValue, double maxValue) { return x < minValue || x > maxValue; }
Если x равен NaN, эта функция неправильно сообщит, что x находится между minValue и maxValue.
Если вы просто хотите, чтобы пользователи проверяли магическое значение, я бы рекомендовал вместо этого положительную или отрицательную бесконечность NaN, поскольку он не имеет таких ловушек. Используйте NaN, если хотите, чтобы его свойство, что любые операции с NaN приводят к NaN: it '
[Edit: мне сначала удалось ввести выше «любые сравнения, в которых они участвуют, будут верными», что не то, что я имел в виду, и это неверно, они все ложны, кроме NaN! = NaN, что верно]
Я думаю, что это вообще плохая идея. Следует иметь в виду, что большинство процессоров обрабатывают Nan намного медленнее, чем "обычный" float. И трудно гарантировать, что у вас никогда не будет Nan в обычных настройках. Мой опыт работы с числовыми вычислениями показывает, что они часто доставляют больше проблем, чем они того стоят.
Правильное решение - избегать кодирования «отсутствия значения» в float, а сигнализировать об этом другим способом. Однако это не всегда практично, в зависимости от вашей кодовой базы.
Я использовал NaN в подобных ситуациях только потому, что из этого: обычное значение инициализации по умолчанию 0 также является допустимым значением. NaN пока работают нормально.
Кстати, хороший вопрос, почему значение инициализации по умолчанию обычно (например, в примитивных типах Java) 0, а не NaN. Разве это не может быть 42 или что-то в этом роде? Интересно, в чем смысл нулей.
Будьте осторожны с NaN ... они могут распространяться как лесной пожар, если вы не будете осторожны.
Они являются вполне допустимым значением для чисел с плавающей запятой, но любые присваивания с их участием также будут равны NaN, поэтому они распространяются через ваш код. Это неплохо в качестве инструмента отладки, если вы его поймаете, однако это также может быть настоящей неприятностью, если вы собираетесь что-то выпустить, и где-то есть крайний случай.
D использует это как обоснование для назначения числа с плавающей запятой NaN по умолчанию . (С чем я не уверен, что согласен.)
Мне кажется, что это немного взломано, но по крайней мере все остальные числа, которые вы выполняете с этим значением NaN, дают NaN как результат - когда вы видите NaN в отчете об ошибке, по крайней мере, вы знаете, за какой ошибкой вы охотитесь.
Если ваша основная потребность состоит в том, чтобы иметь значение с плавающей запятой, которое не представляет никакого числа, которое могло бы быть получено от устройства, и , если устройство гарантирует это никогда не вернет NaN, тогда это кажется мне разумным.
Просто помните, что в зависимости от вашей среды вам, вероятно, понадобится особый способ определения NaN (не используйте просто if (x == float.NaN)
или другой аналог.)
Using NaN as a default value is reasonable.
Note that some expressions, such as (0.0 / 0.0), return NaN.
Мне кажется, это хорошее применение для nans. Хотел бы я подумать об этом ...
Конечно, они должны распространяться как вирус, в этом суть.
Думаю, я бы использовал nan вместо одной из бесконечностей. Было бы неплохо использовать сигнальный nan и заставить его вызывать событие при первом использовании, но к тому времени уже слишком поздно, он должен замолчать при первом использовании.