Действительно ли защищенные члены / поля настолько плохи?
Теперь, если вы прочитаете соглашения об именах в MSDN для C#, вы заметите, что в нем говорится, что свойства всегда предпочтительнее открытых и защищенных полей. Некоторые люди даже говорили мне, что вы никогда не должны использовать открытые или защищенные поля. Теперь я согласен, что мне еще предстоит найти причину, по которой мне нужно открытое поле, но действительно ли защищенные поля настолько плохи?
Я вижу это, если вам нужно убедиться в том, что определенные проверки выполняются при получении / установке значения, однако, на мой взгляд, большую часть времени это кажется просто дополнительными затратами. Я имею в виду, допустим, у меня есть класс GameItem с полями для baseName, prefixName и Суффикс Name. Почему я должен взять на себя оба процесса создания свойств (C#
) или методы доступа и снижение производительности, которое может произойти (если я сделаю это для каждого отдельного поля в приложении, я уверен, что оно будет меньше, особенно в некоторых языках, таких как PHP
или определенные приложения с производительностью критичны как игры)?
6 ответов
Действительно ли защищенные члены / поля настолько плохи?
Нет, они намного, намного хуже.
Как только член более доступен, чем private
вы даете гарантии другим классам о том, как будет вести себя этот член. Поскольку поле полностью неконтролируемо, его размещение "на свободе" открывает ваш класс и классы, которые наследуются или взаимодействуют с вашим классом, для повышения риска ошибок. Нет способа узнать, когда поле меняется, нет способа контролировать, кто или что его меняет.
Если сейчас или в какой-то момент в будущем любой ваш код будет зависеть от поля с каким-то определенным значением, вам теперь нужно добавить проверки достоверности и запасную логику на случай, если это не ожидаемое значение - везде, где вы его используете. Это огромное количество потраченных впустую усилий, когда вы могли бы просто сделать это чертовым свойством;)
Лучший способ поделиться информацией с производными классами - это свойство только для чтения:
protected object MyProperty { get; }
Если вам абсолютно необходимо сделать это для чтения / записи, не надо. Если вы действительно, действительно должны сделать это для чтения-записи, переосмыслите свой дизайн. Если вам все еще нужно это для чтения-записи, извинитесь перед коллегами и не делайте этого снова:)
Многие разработчики верят - и скажут вам - что это слишком строго. И это правда, что вы можете просто обойтись без такой строгости. Но использование этого подхода поможет вам перейти от простого к надежному программному обеспечению. Вы будете тратить гораздо меньше времени на исправление ошибок.
А что касается проблем с производительностью - не надо. Я гарантирую, что вы за всю свою карьеру никогда не будете писать код так быстро, что узким местом будет сам стек вызовов.
ОК, время понижения.
Прежде всего, свойства никогда не повлияют на производительность (при условии, что они не делают много). Это то, что все остальные говорят, и я согласен.
Еще один момент заключается в том, что свойства хороши тем, что в них можно размещать точки останова, чтобы фиксировать события получения / установки и выяснять, откуда они берутся.
Остальные аргументы беспокоят меня таким образом:
Они звучат как "аргумент за престиж". Если MSDN говорит, или какой-то известный разработчик или автор, которого все любят, говорит это, это должно быть так.
Они основаны на идее, что структуры данных имеют много несовместимых состояний и должны быть защищены от блуждания или помещения в эти состояния. Поскольку (как мне кажется) структуры данных переоценены в современном обучении, то обычно они нуждаются в такой защите. Гораздо более предпочтительным является минимизация структуры данных, чтобы она имела тенденцию к нормализации и не имела несовместимых состояний. Затем, если член класса изменяется, он просто изменяется, а не повреждается. В конце концов, как-то много хорошего программного обеспечения было написано / написано на C, и это не сильно пострадало от отсутствия защиты.
Они основаны на защитном кодировании, доведенном до крайности. Это основано на идее, что ваши классы будут использоваться в мире, где нельзя доверять чужому коду, чтобы не обманывать ваши вещи. Я уверен, что есть ситуации, когда это правда, но я никогда не видел их. То, что я видел, - это ситуации, когда все было сделано ужасно сложным, чтобы обойти средства защиты, в которых не было необходимости, и попытаться защитить согласованность структур данных, которые были ужасно сложными и ненормализованными.
Что касается полей по сравнению со свойствами, я могу вспомнить две причины предпочтения свойств в общедоступном интерфейсе (защищенный также является общедоступным в том смысле, что его может видеть только кто-то, кроме вашего класса).
Предоставление свойств дает вам возможность скрыть реализацию. Это также позволяет вам изменять реализацию без изменения кода, который его использует (например, если вы решите изменить способ хранения данных в классе)
Многие инструменты, которые работают с классами, использующими отражение, фокусируются только на свойствах (например, я думаю, что некоторые библиотеки для сериализации работают таким образом). Последовательное использование свойств облегчает использование этих стандартных инструментов.NET.
Что касается накладных расходов:
Если метод получения / установки является обычным однострочным фрагментом кода, который просто считывает / устанавливает значение поля, тогда JIT должен иметь возможность встроить вызов, так что производительность не будет перегружена.
Синтаксические издержки в значительной степени уменьшаются, когда вы используете автоматически реализованные свойства (C# 3.0 и новее), поэтому я не думаю, что это проблема:
protected int SomeProperty { get; set; }
На самом деле, это позволяет сделать, например,
set
защищены иget
public очень легко, так что это может быть даже более элегантно, чем использование полей.
Открытые и / или защищенные поля плохие, потому что ими можно манипулировать извне объявленного класса без проверки; таким образом, можно сказать, что они нарушают принцип инкапсуляции объектно-ориентированного программирования.
Когда вы теряете инкапсуляцию, вы теряете контракт декларирующего класса; Вы не можете гарантировать, что класс ведет себя так, как задумано или ожидается.
Использование свойства или метода для доступа к полю позволяет поддерживать инкапсуляцию и выполнять контракт декларирующего класса.
Это на самом деле зависит от того, является ли ваш класс классом данных или классом поведения.
Если вы храните свое поведение и данные раздельно, то можно представить данные ваших классов данных, если они не имеют поведения.
Если класс является классом поведения, то он не должен предоставлять никаких данных.
Я согласен с ответом свойства только для чтения. Но чтобы сыграть здесь адвоката дьявола, все зависит от того, что вы делаете. Я буду рад признать, что я пишу код с публичными участниками все время (я также не комментирую, не следую указаниям или любым другим формальностям).
Но когда я на работе, это другая история.