Как избежать синглетонов и глобальных переменных - но как насчет кэширования, провайдеров, контроллеров, ...? - PullRequest
2 голосов
/ 16 февраля 2012

В настоящее время я «обновляю» свои знания в области разработки, особенно по принципам TDD, читая книги , статьи в Интернете и просматривая видео . Что-то, что появляется повсюду, - предупреждение, не использовать глобальные переменные состояния, поскольку они делают систему хрупкой и менее легкой для тестирования, и поскольку одиночные пакеты не намного лучше или, скорее, одинаковы, не используйте их тоже.

Теперь мне интересно: могу ли я быть последовательным в этом?

  • А как насчет кеша, который использует приложение, чтобы ему не приходилось искать часто используемые объекты базы данных снова и снова? Мне нужен один экземпляр этого кэша для передачи, иначе какой смысл?
  • Другим примером являются DAO или, как мы их называем, провайдеры. Они делают только доступ к базе данных JPA для нас, но в остальном не имеют никакого состояния. Так почему бы не сделать их синглтоном?
  • А контроллеры в веб-интерфейсе? Все, что они делают, это реагируют на запросы - опять же без внутреннего состояния.

Не будет ли потрачено много времени на создание экземпляров последних двух раз и снова? Я уверен, что есть еще несколько примеров, где это применимо.

Может быть, можно использовать синглтоны, если у них нет переменных-членов, кроме финалов?

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

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

Спасибо!

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

Ответы [ 3 ]

1 голос
/ 17 февраля 2012

Проблема с синглетонами заключается не столько в шаблонах проектирования синглтонов как таковых, сколько в их чрезмерном использовании под обложками, как в глобальных объектах состояния Бога во всех приложениях.

Этот способ использования имеет 2 основных недостатка:

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

  • Объекты зависят от синглетонов, они не имеют никакого представления о том, в каком состоянии они находятся. Порядок, в котором поведение синглтона используется здесь и там, начинает становиться важным, и вы начинаете видеть «MySingleton.Initialize ( ) повсюду, что опасно и побеждает единственную цель иметь один экземпляр.

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

Кроме этого, Singleton-ification чаще всего является преждевременной оптимизацией, примененной к неправильным объектам.

Это сообщение в блоге в значительной степени подводит итог: http://blogs.msdn.com/b/scottdensmore/archive/2004/05/25/140827.aspx

1 голос
/ 16 февраля 2012

Вы абсолютно правы - бывают случаи, когда нужен один экземпляр. Однако бизнес «избегай одиночек» не говорит о том, что они не нужны. В моем понимании говорится, что одноэлементное поведение должно добавляться контейнером зависимостей, а не статическим экземпляром.

Это позволит вам высмеивать его в ваших юнит-тестах, имея только один экземпляр в производстве. Вы можете найти эту ссылку полезной: Области объектов в Ninject

0 голосов
/ 16 февраля 2012

Проблема с синглетонами и глобальными переменными заключается в том, что они нам нужны, но большинство языков программирования предлагают только один «глобальный» контекст.

Представьте, что вы можете сделать это:

 Global g1 = new Global();
 g1.run( ... some code ... );

 Global g2 = new Global();
 g2.run( ... some code ... );

Когда код запускается g2, ни один из синглетонов и глобалов из серии g1 не виден. На самом деле это то, что мы хотим: эффективный способ сказать "хорошо, я закончил с глобальными и прочим, избавиться от них ".

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

Вот что такое «внедрение зависимостей». Вот краткое введение .

...