Какова альтернатива Singleton


У нас есть класс, который хранит информацию о конфигурации для приложения. Это был синглтон. После некоторого архитектурного обзора нам сказали удалить синглтон. Мы видели некоторые преимущества не использования синглтона в модульном тестировании, потому что мы можем тестировать разные конфигурации сразу.

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

13 110

13 ответов:

The блог тестирования Google имеет ряд записей об избежании Синглтона (для того, чтобы создать тестируемый код). Может быть, это может помочь вам:

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

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

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

все ваши объекты будут содержать данные, которые раньше жили в синглтоне. Я не думаю, что есть большая разница в целом, но это может сделать ваш код легче читать.

Я мог бы заявить очевидное здесь, но есть ли причина, по которой вы не можете использовать структуру внедрения зависимостей, такую как Весна или Guice? (Я считаю, что весна также доступна для .NET, а теперь).

таким образом, платформа может содержать одну копию объектов конфигурации, и ваши бобы (службы, DAOs, что угодно) не должны беспокоиться о ее поиске.

Это подход, который я обычно беру!

Если вы используете Spring Framework, вы можете просто создать обычную фасоль. По умолчанию (или если вы явно установите scope="singleton") создается только один экземпляр компонента, и этот экземпляр возвращается каждый раз, когда компонент используется в зависимости или извлекается через getBean().

вы получаете преимущество одного экземпляра, без связи Одноэлементного шаблона.

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

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

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

попробуйте рефакторинг кода, чтобы избежать общего, глобального и большого

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

- Это класс, содержащий только статические методы и поля? Я не совсем уверен в том, что ваша ситуация, но это может быть стоит изучить.

зависит от того, какие инструменты/механизмы и т. д.. используются. С помощью инструментов внедрения зависимостей / ioc часто можно получить одноэлементную производительность/оптимизацию, если контейнер di / ioc использует одноэлементное поведение для требуемого класса (например, интерфейс IConfigSettings), создавая только один экземпляр класса. Это все еще может быть заменено для тестирования

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

обзор возможности сделать конфигурацию в качестве интерфейса обратного вызова. Так что ваша конфигурация чувствительный код будет выглядеть:

MyReuseCode.Configure(IConfiguration)

System-init код будет выглядеть:

Library.init(MyIConfigurationImpl)

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

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

public static Singleton getInstance() {
    if(singleton != null)
        createSingleton();
        return singleton;
    }
}

можно назвать createSingleton(Information info) непосредственно при запуске приложения (а в настройках-методы модульных тестов).

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

DI используя весну, etc, очень хороший вариант но не единственный вариант.