Какая альтернатива 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 и т.д. - очень хороший вариант, но не единственный вариант.