Что является альтернативой синглтон - PullRequest
113 голосов
/ 19 августа 2009

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

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

Ответы [ 13 ]

127 голосов
/ 19 августа 2009

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

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

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

15 голосов
/ 19 августа 2009

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

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

5 голосов
/ 19 августа 2009

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

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

Такой подход я обычно использую!

4 голосов
/ 19 августа 2009

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

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

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

class Server {

    int port;

    Server(Configuration config) {
        this.port = config.getServerPort();
    } 

}

должен быть изменен на:

 class Server {

    public Server(int port) {
       this.port = port;
    }
 }

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

4 голосов
/ 19 августа 2009

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

4 голосов
/ 19 августа 2009

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

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

1 голос
/ 19 августа 2009

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

0 голосов
/ 31 июля 2012

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

DI, использующий Spring и т. Д., Является очень хорошим вариантом, но не единственным.

0 голосов
/ 19 августа 2009

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

0 голосов
/ 19 августа 2009

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

MyReuseCode.Configure(IConfiguration)

Код инициализации системы будет выглядеть:

Library.init(MyIConfigurationImpl)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...