«Синглтон» заводы, хорошо или плохо?

У меня много (абстрактных) фабрик, и они обычно реализуются как синглтоны.

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

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

это выглядит, например, любить

abstract class ColumnCalculationFactory { 
  private static ColumnCalculationFactory factory;

 public static void SetFactory(ColumnCalculationFactory f) {
         factory = f;
  }

  public static void Factory() {
         return factory;
  }

 public IPercentCalculation CreatePercentCalculation();
 public IAverageCalculation CreateAverageCalculation();
    ....

}

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

Это считается лучшей практикой? Должен ли я добавить их в некоторый (полу) глобальный класс AppContext? Что-то еще (я не совсем готов переключиться на какой-нибудь более крупный контейнер IoC или Spring.net, кстати, пока что)?

Ответы на вопрос(6)

Я не вижу проблем: вы сказали «моим программам больше не нужно», поэтому вы можете реализовать что-то более гибкое / абстрактное.Вам это не нужно.

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

Миско Хевери имеетхорошая статья Об этом в своем блоге.

 Adam Calvet Bohl13 янв. 2017 г., 07:11
Спасибо! Статья Миско великолепна, и комментарии стоит прочитать!
 Adam Calvet Bohl13 янв. 2017 г., 07:39
Также стоит прочитать:misko.hevery.com/2008/10/21/...
 nos16 авг. 2009 г., 21:44
С помощью приведенного выше кода вы можете легко издеваться над фабрикой.
 jqno16 авг. 2009 г., 21:49
Конечно, но не могли бы вы сразу узнать, какие из них вам нужно высмеять, в нетривиальном приложении, где вы не знаете зависимости класса наизусть? Я снова ссылаюсь на статью Миско.
 Despertar22 авг. 2013 г., 01:40
Миско также имеет несколько отличных видео на YouTube на эту тему,youtube.com/watch?v=acjvKJiOvXw
Решение Вопроса

что вы делаете и от сферы применения. Если это просто довольно маленькое приложение, и оно никогда не выйдет за рамки этого, тогда ваш нынешний подход вполне может подойти. Для этих вещей не существует универсальной «лучшей» практики. Хотя я бы не рекомендовал использовать синглеты для чего-либо, кроме листовых методов без сохранения состояния и / или односторонних вызовов (например, ведения журнала), отклонять их из-под контроля «просто потому, что» это синглтон, не обязательно правильно.

Для чего-то другого, кроме тривиального кода или кода-прототипа, мне лично нравится явно использовать инверсию управления с инжекцией в конструктор, поскольку это означает, что все зависимости учтены, и вы не получите никаких «сюрпризов». Компилятор не позволит вам создать экземпляр A без B и B без C. Синглтоны немедленно похоронят эти отношения - вы можете создать экземпляр A без B и B без C. Когда произойдет вызов из A в B, вы получите нулевую ссылку исключение.

Это особенно раздражает при тестировании, так как вам приходится многократно работать в обратном направлении через сбои во время выполнения. Когда вы тестируете код, вы используете API так же, как это делал бы другой программист, поэтому это свидетельствует о проблемах проектирования с этим подходом. Внедрение в конструктор гарантирует, что этого никогда не произойдет - все зависимости указаны заранее. Недостатком внедрения в конструктор является то, что конфигурация графа вашего объекта более сложна. Это смягчается за счет использования контейнера IoC.

Я предполагаю, что я пытаюсь сказать, что если вы дошли до того, что рассматриваете возможность использования какого-либо объекта контекста и шаблона реестра, вы можете также взглянуть на контейнеры IoC. Попытка развернуть собственную версию Mutt - это, вероятно, пустая трата времени, когда вы можете использовать установленный бесплатный продукт, такой как Autofac.

 Chrips27 авг. 2018 г., 05:56
Могу ли я использовать шаблон для инверсии управления, который не включает Spring и XML? Я не знаю, как использовать IC для «предварительной загрузки» конструкторов без Spring и, следовательно, веб-проекта. А как насчет не веб-проектов?

потому что то, что вы делаете здесь, создает глобальное состояние. Существуют всевозможные проблемы с глобальным состоянием, главным из которых является то, что одна функция затем довольно незаметным образом зависит от поведения других функций. Если функция вызывает другую функцию, которая забывает хранить и восстанавливатьfactory до его завершения возникает проблема, потому что вы не можете даже вернуть старое значение, пока не сохраните его где-то И вы должны добавить код, чтобы сделать это (судя по вашему коду, я думаю, вы на языке сfinally, что оставляет еще больше места для ошибок). Более того, если вы в конечном итоге получите код, который должен быстро переключаться между двумя фабриками для двух подобъектов, вы должны написать вызов метода в каждой точке - вы не можете сохранить состояние в каждом подобъекте (ну, вы можете, но потом Вы побеждаете цель глобального государства (которое, по общему признанию, не так много)).

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

 leeeroy16 авг. 2009 г., 21:34
хотя, учитывая открытую общедоступную SetFactory, нет никакой гарантии, что кто-то не сможет обменяться беспорядком с фабрикой, я обычно устанавливаю фабрику только при запуске, основываясь на первоначальном решении или конфигурации.
 coppro16 авг. 2009 г., 21:38
тогда вы становитесь жертвой недостатка синглетонов ... они синглтоны.

чно - большое количество синглетонов приводит к некоторому раздражающему коду.

Мы только что столкнулись с ситуацией, когда нам пришлось тестировать наши тяжелые синглтон-классы. Проблема заключается в том, что когда вы тестируете класс b и он получает класс c (одноэлементный), у вас нет возможности макетировать класс c (по крайней мере, EasyMock не позволил бы нам заменить статический метод фабрики одноэлементного класса.

Одно простое решение - иметь «сеттеры» для всех ваших синглетонов для тестирования. Не очень рекомендуется.

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

Помимо тестирования, я давно узнал, что когда-либо никогда не будет более одного экземпляра данного объекта; в следующем издании они часто хотят два, что делает синглтоны НАМНОГО лучше, чем статические классы - по крайней мере, вы можете добавить параметр в метод получения одиночного кода и вернуть второй без особого рефакторинга (который снова просто делает то, что делает DI) ).

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

 Trenton23 авг. 2009 г., 06:13
Согласовано. Еще одним следствием синглетонов является «утечка» заданных значений во время модульных тестов. В результате мы должны были разветвлять JVM для каждого теста, поскольку тестируемый одноэлементный тест или просто используемый тестом находился в состоянии A, а нижестоящий - в состоянии B.
 user322531322 июл. 2016 г., 18:18
Проблема с расширенным TDD заключается в том, что вы часто усложняете код и делаете его более подверженным ошибкам ради использования инструментов тестирования. Я твердо верю, что если вам нужно изменить архитектуру ради Mocking, вы злоупотребляете Mocking и вместо этого должны использовать предполагаемую конфигурацию Factory / Singleton. 100% покрытие кода безумно и вызовет больше проблем и сложностей, чем решит.
 Bill K22 июл. 2016 г., 19:06
Я согласен с TDD, но это не единственная причина использовать DI. Кроме того, TESTABLE-код, как правило, будет лучше, чем непроверяемый, независимо от фактического существования тестов. Наличие DI вместо синглтона не всегда плохо и может быть очень полезно в том случае, если вы действительно хотите его протестировать, даже если у вас нет 100% тестового покрытия.

которая реализует эквивалент вашего метода Factory с:

return new CalculationFactory ();

Это гораздо сложнее заглушить, издеваться или обернуть.

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

Ваш ответ на вопрос