2010-07-03 2 views
7

Я был веб-разработчиком в течение некоторого времени, используя ASP.NET и C#, я хочу попробовать и повысить свои навыки, используя лучшие практики.Альтернативы для одноэлементного шаблона?

У меня есть веб-сайт. Я хочу загрузить настройки после выключения и просто ссылаться на него, когда мне это нужно. Поэтому я сделал некоторые исследования, и 50% разработчиков, похоже, используют шаблон singleton для этого. А остальные 50% разработчиков - ант-синглтон. Они все ненавидят одиночки. Они рекомендуют инъекцию зависимости.

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

Благодаря Brendan

+0

Возможный дубликат [Существуют ли жизнеспособные альтернативы шаблону Singleton в GOF?] (Http://stackoverflow.com/questions/162042/are-there-any-viable-alternatives-to-the-gof-singleton- pattern) –

ответ

6

Как правило, я избегаю синглетов, потому что они затрудняют тестирование вашего приложения. Синглтоны трудно объединиться для модульных тестов именно из-за их характера - вы всегда получаете то же самое, а не одно, которое вы легко конфигурируете для модульного теста. Конфигурационные данные - строго типизированные данные конфигурации, во всяком случае - это одно исключение, которое я делаю. Как правило, данные конфигурации относительно статичны в любом случае, и альтернатива предполагает запись достаточного количества кода, чтобы избежать статических классов, которые обеспечивает инфраструктура для доступа к web.config.

Существует несколько способов его использования, которые по-прежнему позволят вам выполнить тестирование вашего приложения. Один из способов (возможно, оба способа, если ваш синглтон не лениво читает app.cofnig) должен иметь файл app.config по умолчанию в вашем проектном модульном проекте, предоставляющем значения по умолчанию, необходимые для ваших тестов. Вы можете использовать рефлексию для замены любых конкретных значений по мере необходимости в модульных тестах. Как правило, я настраивал бы частный метод, который позволяет удалить отдельный экземпляр singleton в тестовой настройке, если я вношу изменения для конкретных тестов.

Другой способ заключается в том, что на самом деле не использовать Singleton напрямую, а создать для него интерфейс, который реализует класс singleton. Вы можете использовать ручную инъекцию интерфейса, по умолчанию для экземпляра singleton, если заданное значение равно null. Это позволяет создать экземпляр mock, который вы можете передать тестируемому классу для своих тестов, но в вашем реальном коде используется экземпляр singleton. По сути, каждый класс, который в нем нуждается, поддерживает частную ссылку на экземпляр singleton и использует его. Мне нравится этот способ немного лучше, но поскольку синглтон будет создан, вам все равно может понадобиться файл app.config по умолчанию, если все значения не будут загружены лениво.

public class Foo 
{ 
    private IAppConfiguration Configuration { get; set; } 

    public Foo() : this(null) { } 

    public Foo(IAppConfiguration config) 
    { 
     this.Configuration = config ?? AppConfiguration.Instance; 
    } 

    public void Bar() 
    { 
     var value = this.Config.SomeMaximum; 
     ... 
    } 
}  
+0

Простите так поздно. интересные комментарии о Конфигурационных данных в качестве исключения. Обычно я придерживаюсь противоположного подхода. Я пытаюсь реализовать свою конфигурацию во время выполнения в качестве интерфейсов и внедрить их в приложение при запуске. Таким образом, моя программа зависит только от самих интерфейсов, которые могут свободно меняться или издеваться над тестированием. При запуске мне нужно читать объекты с помощью ConfigurationManager, но это единственное место, которое знает об этом статическом классе. – user734929

+0

Это тот подход, к которому я также подключился, хотя мой конфигурационный интерфейс зарегистрирован как одиночный элемент в моем контейнере DI для лучшего из обоих миров. Тем не менее, это все-таки единственный пример реализации Singleton, с которым я чувствую себя комфортно. – tvanfosson

1

Там хорошее обсуждение одноэлементных узоров и кодирование здесь примеры ... http://en.wikipedia.org/wiki/Singleton_pattern Смотрите также здесь ... http://en.wikipedia.org/wiki/Dependency_injection

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

+0

Я хочу также проверить его, но не знаю, как выполнить модульный анализ одноэлементного шаблона? –

1

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

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

+0

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

+3

@Brian: Этот шаблон описан на http://sites.google.com/site/steveyegge2/singleton-considered-stupid – wRAR

+0

У вас есть образец кода того, что вы описали? Или ссылку? –

0

Один из способов решения этой проблемы - выбить ее из-за проблемы DAL .

Независимо от того, какой класс/веб-страница и т. Д. Должен использовать настройки конфигурации, следует объявить зависимость от IConfigSettingsService (фабрика/репозиторий/независимо от того, как вы их используете).

private IConfigSettingsService _configSettingsService; 

public WebPage(IConfigSettingsService configSettingsService) 
{ 
    _configSettingsService = configSettingsService; 
} 

Так что ваш класс будет получить настройки, как это:

ConfigSettings _configSettings = _configSettingsService.GetTheOnlySettings(); 

реализация ConfigSettingsService будет иметь зависимость, которая является классом Дали. Как бы этот Dal заполнил объект ConfigSettings? Кому это нужно.

  • Может быть, это было бы заселить ConfigSettings из XML в базу данных или файл .config, каждый раз.

  • Возможно, он делает это в первый раз, а затем заполняет статические _configSettings для последующих вызовов.

  • Возможно, он получит настройки от Redis. Если что-то указывает на изменение настроек, тогда dal или что-то внешнее может обновить Redis. (Этот подход будет полезен, если у вас есть более одного приложения, используя настройки.

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

На самом деле это скорее будет MyPageBase, у которого есть зависимость IConfigSettingsService, но это может быть просто как веб-служба, служба Windows, MVC somehatsit, так и все вышеперечисленное.

Смежные вопросы