Какая альтернатива Singleton
У нас есть класс, содержащий информацию о конфигурации для приложения. Раньше это был синглтон. После некоторого архитектурного обзора нам сказали снять синглтон. Мы увидели некоторые преимущества использования Singleton в модульном тестировании, так как мы можем тестировать разные конфигурации одновременно.
Без singleton мы должны передавать экземпляр вокруг везде в нашем коде. Это становится настолько беспорядочным, что мы написали обертку с одиночной оболочкой. Теперь мы переносим один и тот же код на PHP и .NET. Мне интересно, есть ли лучший шаблон, который мы можем использовать для объекта конфигурации.
Ответы
Ответ 1
Блог Google Тестирование содержит ряд записей об исключении Singleton (для создания тестового кода). Возможно, это может вам помочь:
В последней статье подробно описывается, как перемещать создание новых объектов в factory, поэтому вы можете избежать использования синглетонов. Стоит прочитать наверняка.
Короче говоря, мы переносим все новые операторы на factory. Мы группируем все объекты одинакового времени жизни в один factory.
Ответ 2
Лучше всего использовать шаблон Factory. Когда вы создаете новый экземпляр вашего класса (в factory), вы можете вставить глобальные данные в вновь созданный объект, либо в качестве ссылки на один экземпляр (который вы храните в классе Factory), либо путем копирования соответствующих данных в новый объект.
Все ваши объекты затем будут содержать данные, которые использовались для жизни в одноэлементном режиме. Я не думаю, что в целом разница в целом, но это может сделать ваш код более легким для чтения.
Ответ 3
Я мог бы заявить очевидное здесь, но есть ли причина, по которой вы не можете использовать инфраструктуру внедрения зависимостей, такую как Spring или Guice? (Я считаю, что Spring также доступен и для .NET теперь).
Таким образом, инфраструктура может содержать одну копию объектов конфигурации, а ваш beans (сервисы, DAOs, что угодно) не должен беспокоиться о поиске.
Это подход, который я обычно беру!
Ответ 4
Если вы используете Spring Framework, вы можете просто создать обычный bean. По умолчанию (или если вы явно устанавливаете scope="singleton"
) создается только один экземпляр bean, и этот экземпляр возвращается каждый раз, когда bean используется в зависимости или извлекается через getBean()
.
Вы получаете преимущество единственного экземпляра без связи шаблона Singleton.
Ответ 5
Альтернатива - это то, что вам нужно, вместо того, чтобы задавать объект для вещей.
Ответ 6
не накапливать responsibilites для одного объекта конфигурации, поскольку он заканчивается очень большим объектом, который трудно понять и хрупко.
Например, если вам нужен другой параметр для определенного класса, вы меняете объект Configuration
, а затем перекомпилируете все классы, которые его используют. Это несколько проблематично.
Попробуйте рефакторинг кода, чтобы избежать общего, глобального и большого объекта Configuration
. Передайте только требуемые параметры для классов клиента:
class Server {
int port;
Server(Configuration config) {
this.port = config.getServerPort();
}
}
должен быть реорганизован на:
class Server {
public Server(int port) {
this.port = port;
}
}
a инфраструктура инъекции зависимостей поможет здесь много, но это не требуется.
Ответ 7
Является ли класс, который содержит только статические методы и поля? Я не уверен, в чем именно заключается ваша ситуация, но, возможно, стоит заглянуть в нее.
Ответ 8
Может быть, и не очень чистый, но вы могли бы передать информационные биты, которые хотите изменить, на метод, который создает синглтон, вместо использования
public static Singleton getInstance() {
if(singleton != null)
createSingleton();
return singleton;
}
}
вы можете вызвать createSingleton(Information info)
непосредственно при запуске приложения (и в setUp-Методах модульных тестов).
Ответ 9
Зависит от того, какие инструменты/рамки и т.д. используются.
С помощью средств инжекционного ввода /ioc вы часто можете получать производительность/оптимизацию singleton, используя контейнер single/di для использования в классе singleton (например, интерфейс IConfigSettings), создавая только один экземпляр класса. Это может быть все еще заменено на тестирование
В качестве альтернативы можно было бы использовать factory для создания класса и возвращать один и тот же экземпляр каждый раз, когда вы его запрашиваете, но для тестирования он может вернуть зашифрованную/издеваемую версию
Ответ 10
Просмотрите возможность настройки в качестве интерфейса обратного вызова.
Таким образом, ваш конфигурационный чувствительный код будет выглядеть:
MyReuseCode.Configure(IConfiguration)
Появится код System-init:
Library.init(MyIConfigurationImpl)
Ответ 11
Вы можете использовать инфраструктуру инъекций зависимостей, чтобы облегчить боль при передаче в объекте конфигурации. Порядочный ninject, который имеет преимущество использования кода, а не xml.
Ответ 12
Вы можете выполнить одно и то же поведение singleton с помощью статических методов. Стив yegge очень хорошо объясняет это в этой публикации.
Ответ 13
Синглтоны не злые, но шаблон дизайна ошибочен. У меня есть класс, который я хочу создать только один экземпляр во время выполнения, но хочу создать несколько изолированных экземпляров во время модульного тестирования, чтобы обеспечить детерминированные результаты.
DI с использованием Spring и т.д. - очень хороший вариант, но не единственный вариант.