Почему статические переменные считаются злом?
Я программист на Java, новичок в корпоративном мире. Недавно я разработал приложение, используя Groovy и Java. На протяжении всего написанного мной кода использовалось довольно много статики. Старший технический специалист попросил меня сократить количество используемой статики. Я погуглил примерно то же самое и обнаружил, что многие программисты категорически против использования статических переменных.
Я нахожу статические переменные более удобными в использовании. И я предполагаю, что они тоже эффективны (пожалуйста, поправьте меня, если я ошибаюсь), потому что, если бы мне пришлось совершить 10 000 вызовов функции внутри класса, я был бы рад сделать метод статическим и использовать для него простой Class.methodCall()
вместо того, чтобы загромождать память 10 000 экземпляров класса, верно?
Более того, статика уменьшает взаимозависимости от других частей кода. Они могут выступать в качестве идеальных держателей состояний. Добавляя к этому, я обнаружил, что статика широко реализована в некоторых языках, таких как Smalltalk и Scala. Так почему же это неприятие статики распространено среди программистов (особенно в мире Java)?
PS: пожалуйста, поправьте меня, если мои предположения о статике неверны.
Переведено автоматически
Ответ 1
Статические переменные представляют глобальное состояние. Об этом трудно рассуждать и трудно тестировать: если я создаю новый экземпляр объекта, я могу рассуждать о его новом состоянии в тестах. Если я использую код, использующий статические переменные, он может находиться в любом состоянии - и что угодно может его изменять.
Я мог бы продолжать довольно долго, но более масштабная концепция, о которой стоит подумать, заключается в том, что чем шире область действия чего-либо, тем легче рассуждать об этом. Мы умеем думать о мелочах, но трудно рассуждать о состоянии системы из миллиона строк, если нет модульности. Кстати, это применимо ко всем видам вещей, а не только к статическим переменным.
Ответ 2
Это не очень объектно-ориентированный метод: Одна из причин, по которой некоторые люди могут считать статику "злом", заключается в том, что она противоречит объектно-ориентированной парадигме. В частности, это нарушает принцип, согласно которому данные инкапсулируются в объекты (которые можно расширять, скрывать информацию и т.д.). Статика, в том виде, в каком вы описываете их использование, по сути, заключается в использовании их в качестве глобальной переменной, чтобы избежать решения таких проблем, как область видимости. Однако глобальные переменные являются одной из определяющих характеристик парадигмы процедурного или императивного программирования, а не характеристикой "хорошего" объектно-ориентированного кода. Это не значит, что процедурная парадигма плоха, но у меня складывается впечатление, что ваш руководитель ожидает, что вы будете писать "хороший объектно-ориентированный код", а вы действительно хотите написать "хороший процедурный код".
Когда вы начинаете использовать статику, в Java возникает много ошибок, которые не всегда сразу бросаются в глаза. Например, если у вас есть две копии вашей программы, запущенные на одной виртуальной машине, не изменят ли они значение статической переменной и состояние друг друга? Или что происходит, когда вы расширяете класс, можете ли вы переопределить статический элемент? Вашей виртуальной машине не хватает памяти, потому что у вас безумное количество статических данных, и эта память не может быть освобождена для других необходимых объектов экземпляра?
Время жизни объекта: Кроме того, у статики есть время жизни, соответствующее всему времени выполнения программы. Это означает, что даже после того, как вы закончите использовать свой класс, память из всех этих статических переменных не может быть собрана мусором. Если, например, вместо этого вы сделали свои переменные нестатическими, и в вашей функции main () вы создали единственный экземпляр своего класса, а затем попросили свой класс выполнить определенную функцию 10 000 раз, после того, как эти 10 000 вызовов были выполнены, и вы удалили свои ссылки на единственный экземпляр, все ваши статические переменные могли быть собраны в мусор и использованы повторно.
Предотвращает определенное повторное использование: Кроме того, статические методы нельзя использовать для реализации интерфейса, поэтому статические методы могут препятствовать использованию определенных объектно-ориентированных функций.
Другие варианты: Если эффективность является вашей главной заботой, могут быть другие лучшие способы решения проблемы скорости, чем рассмотрение только преимущества того, что вызов обычно быстрее создания. Подумайте, нужны ли где-либо модификаторы transient или volatile . Чтобы сохранить возможность встраивания, метод может быть помечен как final вместо static . Параметры метода и другие переменные могут быть помечены как окончательные, чтобы разрешить определенные оптимизации компилятора, основанные на предположениях о том, что может изменить эти переменные. Объект экземпляра можно использовать повторно несколько раз, а не создавать каждый раз новый экземпляр. Возможно, существуют переключатели оптимизации комплайнера, которые следует включить для приложения в целом. Возможно, дизайн следует настроить так, чтобы 10 000 запусков могли быть многопоточными и использовать преимущества многопроцессорных ядер. Если переносимость не вызывает беспокойства, возможно, собственный метод обеспечит вам лучшую скорость, чем ваша статика.
Если по какой-то причине вы не хотите создавать несколько копий объекта, то шаблон проектирования singleton имеет преимущества перед статическими объектами, такие как потокобезопасность (при условии, что ваш singleton хорошо закодирован), допускающий отложенную инициализацию, гарантирующий правильную инициализацию объекта при его использовании, подклассы, преимущества в тестировании и рефакторинге вашего кода, не говоря уже о том, что если в какой-то момент вы передумаете использовать только один экземпляр объекта, гораздо проще удалить код для предотвращения дублирования экземпляров, чем его заключается в рефакторинге всего вашего кода статических переменных для использования переменных экземпляра. Мне приходилось делать это раньше, это не весело, и в конечном итоге вам приходится редактировать гораздо больше классов, что увеличивает риск введения новых bugs...so гораздо лучше настроить все "правильно" с первого раза, даже если кажется, что у этого есть свои недостатки. Для меня необходимая доработка, если в будущем вы решите, что вам нужно несколько копий чего-либо, вероятно, является одной из наиболее веских причин использовать статику как можно реже. И, таким образом, я бы также не согласился с вашим утверждением, что статика уменьшает взаимозависимости, я думаю, в конечном итоге вы получите более связанный код, если у вас будет много статики, к которой можно получить прямой доступ, а не объект, который "знает, как что-то сделать" сам по себе.
Ответ 3
Зло - это субъективный термин.
Вы не контролируете статику с точки зрения создания и уничтожения. Они существуют по воле загрузки и выгрузки программы.
Поскольку статика находится в одном пространстве, все потоки, желающие их использовать, должны проходить контроль доступа, которым вы должны управлять. Это означает, что программы более взаимосвязаны, и это изменение сложнее предусмотреть и управлять им (как говорит Дж. Скит). Это приводит к проблемам изоляции влияния изменений и, таким образом, влияет на то, как управляется тестирование.
Это две основные проблемы, с которыми я сталкиваюсь.
Ответ 4
Нет. Глобальные состояния сами по себе не являются злом. Но мы должны просмотреть ваш код, чтобы понять, правильно ли вы его использовали. Вполне возможно, что новичок злоупотребляет глобальными состояниями; точно так же, как он злоупотребил бы любой функцией языка.
Глобальные состояния являются абсолютной необходимостью. Мы не можем избежать глобальных состояний. Мы не можем избежать рассуждений о глобальных состояниях. - Если мы хотим понять семантику нашего приложения.
Люди, которые пытаются избавиться от глобальных состояний ради этого, неизбежно получают в итоге гораздо более сложную систему - и глобальные состояния все еще там, умно / идиотски замаскированные под многими слоями косвенных ссылок; и нам все еще приходится рассуждать о глобальных состояниях, после того как мы развернем все косвенные ссылки.
Как и люди из Spring, которые щедро объявляют глобальные состояния в xml и думают, что это каким-то образом лучше.
@Джон Скит if I create a new instance of an object
теперь вам нужно рассуждать о двух вещах - состоянии внутри объекта и состоянии среды, в которой размещен объект.