Действительно ли защищенные члены / поля настолько плохи?

Теперь, если вы прочитаете соглашения об именах в 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 очень легко, так что это может быть даже более элегантно, чем использование полей.

Открытые и / или защищенные поля плохие, потому что ими можно манипулировать извне объявленного класса без проверки; таким образом, можно сказать, что они нарушают принцип инкапсуляции объектно-ориентированного программирования.

Когда вы теряете инкапсуляцию, вы теряете контракт декларирующего класса; Вы не можете гарантировать, что класс ведет себя так, как задумано или ожидается.

Использование свойства или метода для доступа к полю позволяет поддерживать инкапсуляцию и выполнять контракт декларирующего класса.

Это на самом деле зависит от того, является ли ваш класс классом данных или классом поведения.

Если вы храните свое поведение и данные раздельно, то можно представить данные ваших классов данных, если они не имеют поведения.

Если класс является классом поведения, то он не должен предоставлять никаких данных.

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

Но когда я на работе, это другая история.

Другие вопросы по тегам