Статьи

Что такого плохого в Синглтоне?

Я продолжаю сталкиваться с людьми, которые предостерегают от использования Синглтона и рекомендую избегать его как чумы. Что в этом страшного?
Кайлаш Баду

Это хороший вопрос, потому что это правда, что глобальные переменные часто демонизируются, и в последнее время Синглтон постигла та же участь. Возможно, это немного удивительно, но найти достаточно веские аргументы в поддержку этих общих знаний очень сложно — поиск в Google приводит к путанице.

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

Анатомия Синглтона

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

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

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

Но я забегаю вперед.

Состояние программы

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

Поскольку основной единицей программы является функция, состояние обычно относится к данным, которые относятся к функции. Функция называется состоящей из состояний, если она меняет свой контекст, при запуске или если контекст оказывает какое-либо влияние на результат функции. Иногда термин «побочные эффекты» используется для описания того же. Функция называется чистой , если она всегда выдает один и тот же вывод при одинаковом вводе. Например, следующее является чистой функцией:


function add($a, $b) {
  return $a + $b;
}

В той же терминологии функция, которая не является чистой, называется процедурой . Отсюда и термин « процедурное программирование» . Ниже приведен пример процедуры:

 
function add($a, $b) {
  echo ($a + $b);
}

Разные оттенки состояния

Глобальные переменные — это определенный тип состояния программы, но он не единственный. Приведенный выше пример (2) имеет побочный эффект без использования глобальной переменной — он записывает в стандартный вывод. Другой распространенный тип состояния — это изменчивые объекты. Например, объект, имеющий setName() Даже локальная переменная является состоящей из тела функции. Хотя это все примеры состояния, они представляют разные степени на шкале.

В чем проблема, опять же?

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

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

Другая проблема — это проблема сцепления. Поскольку состояние может совместно использоваться различными функциями, оно может вводить зависимость между этими функциями. Например, если классы ABGGAB Этот вид зависимости называется связью .

В программах есть средства от чрезмерного состояния: глобальные переменные могут быть заменены локальными. Локальные переменные можно заменить вызовами функций ( замените temp запросом ). Объекты, которые передаются, можно сделать неизменными — это особенно важно для долгоживущих объектов, которые взаимодействуют со многими сторонами .

Статическая привязка

Программа имеет два разных типа существования; Время компиляции и время выполнения. Интерпретируемые языки чередуются между ними, в то время как скомпилированный язык имеет более строгое разделение. В любом случае, символы программы, которые принимают значение во время компиляции, не могут изменить его значение во время выполнения. Примерами таких символов являются константы, литералы, имена классов и статические методы (и в PHP плавающие функции ). Символы времени выполнения (переменные), с другой стороны, могут менять свое значение.

Несмотря на то, что статические символы не могут измениться, они все же могут влиять на результат функции, поэтому в очень общем смысле они являются формой состояния. Обычно не так важно избегать состояния статических символов, но в некоторых случаях они могут вызывать те же проблемы, что и состояние во время выполнения. Например, вызовы статических методов вызывают статическую (во время компиляции) связь. Синглтон является ярким примером такого рода связи; Если в классе A используется синглтон S, то существует сильная связь между A и S.

связь

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

Это все

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

Прости меня, отец, потому что у меня есть Singleton’ed
Кевлин Хенни

Комментарии — как всегда — приветствуются, но, пожалуйста, воздержитесь от откусывания голов (моих или других).