Почему многие разработчики возражают против использования "защищенного" модификатора в ООП?

Один из моих коллег занимается внедрением класса объектно-ориентированного программирования, и его профессор спросил:

Почему многие разработчики возражают против использования "защищенного" модификатора внутри/внутри классов?

Когда вопрос был поднят за обедом, мои коллеги и я не могли думать о причинах, по которым кто-то может возражать против использования модификатора protected в классе. Устанавливая предпосылку вопроса в сторону (который предполагает, что многие разработчики фактически выступают против модификатора protected, являются ли они?), Мы попытались выяснить, почему.

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

Почему разработчики могут возражать против использования модификатора protected в их дизайне ООП?

ПРИМЕЧАНИЕ. Поскольку профессор задает общий вопрос ООП, не относящийся ни к одному языку, я не уверен, что ответы могут быть взвешены по-разному из-за различных реализаций protected в С#, Java и т.д.

Ответ 1

Разработчики не жалуются на защиту, пока они не позволят разработчику добраться до того, что они хотят использовать. Для разработчиков, которые создают дочерние классы, защита не имеет большого значения, потому что они будут иметь доступ к товарам из своих дочерних классов.

Для разработчиков, которые используют данный класс (не расширяя его), защищенные блокируют доступ к потенциально сочным деталям внутренней реализации. Это то, о чем они будут беспокоиться.

Можно сказать, что некоторые разработчики фреймов слишком сильно ошибаются в стороне конфиденциальности - запрещают доступ ко всему и разрешают доступ только к определенным документально подтвержденным функциям. Это может расстраивать, когда вы знаете, что внутри вы можете найти хорошие вещи, которые вы могли бы использовать для решения вашей непосредственной проблемы, но подумайте об обратном: если ваша инфраструктура была разработана кем-то, кто предоставил свободный доступ ко всему, все внутренние детали вы, вероятно, столкнетесь с одной из двух вещей, когда инфраструктура будет обновлена ​​в какой-то момент в будущем:

  • Обновленная каркас изменяет детали реализации, которые зависят от вашего кода, и ваш код нарушает
  • Дизайнеры понимают, что они не могут изменить реализацию, не разбирая много кода, поэтому они предпочитают не реализовывать полезные функции или исправления ошибок. Это называется паралич кода.

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

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

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

Инкапсуляция - это хорошо, даже если она блокирует кратчайший путь к решению.; >

Ответ 2

потому что взаимодействие с объектом превосходит наследование.

Джеймс Гослинг, как сообщается, сказал, что если он снова сделает Яву, он будет без классов, и пояснил бы, что под "классами" он подразумевал наследование. protected не имеет смысла (или сводится к private) без наследования (хотя и не в Java), но с наследованием он взрывается в слизистую публичную дегенерацию, а тем более в Java (Программирование Scala глава 5).

Аллен Голуб пишет (в Holub on Patterns, которая является Java-книгой, но отличная от общей перспективы ООП), что protected является public другим именем, особенно в Java, где. защищенный символ - это тот, которому нельзя доверять, чтобы быть тем, что вы видите внутри класса, в котором он был объявлен. Другие классы (потомки) могут менять его под нос. вы имеете дело с эффектом yo-yo.

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

Ответ 3

Без обширного опроса я просто угадываю здесь, говоря в основном об защищенном модификаторе применительно к функциям-членам.

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

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

В качестве примера предположим, что у вас есть достаточно полная библиотека интерфейса, которая предоставляет класс CImage. Ваш экран-растровый механизм "блокирует" этот класс CImage во время рисования. Но ваш класс CImage обеспечивает защищенную функцию "getPixel()". Пользователь вашей библиотеки перегрузил эту функцию для собственного использования в другом месте и попытался заблокировать изображение. Такая проблема очень важна для связи в документации, и это просто боль в шее для обработки каждой защищенной функции-члена или части функциональности.

Ответ 4

Во-первых, protected не является гарантией конфиденциальности, если только единственный потребляемый класс в вашей цепочке наследования не запечатан (т.е. все базовые классы являются внутренними для сборки). Любой разработчик, который знает НИЧЕГО о ООП, может вывести ваш класс и разоблачить все ваши внутренности в мире.

Использование internal для членов вместо этого обычно решает эту проблему; только ВАШ код, расположенный в той же сборке, которую вы разрабатываете, может видеть внутренний член. Публичные дети, которых вы выставляете для использования другими, могут быть получены извне собрания, но внутренности, которые вы хотите скрывать, по-прежнему скрыты. Разработчики, создающие дочерние объекты или другие объекты в одной и той же сборке, должны обмениваться информацией с вами о том, что они используют, если ваши внутренние компоненты действительно чувствительны с точки зрения времени выполнения. Помните, что protected internal означает защищенный ИЛИ внутренний, не защищенный И внутренний.

Во-вторых, protected обычно указывает на некоторые недостатки в дизайне классов, особенно если используются как защищенные, так и общедоступные. Если у вас есть секрет, но вы должны поделиться им со своими детьми, это не секрет, и, вероятно, это должно быть публично. Если это ДЕЙСТВИТЕЛЬНО секрет, вашим детям не следует доверять это, потому что, если вы не дадите своим детям вазэктомию с ключевым словом sealed, вы не можете запретить им рассказывать своим детям, которые больше не могут думать об этом секрет и поделиться им со своей семьей или миром.

Использование protected не страшно, но просто не выполняет то, на что многие разработчики хотят его использовать; чтобы сделать класс снаружи доступным для "доверенных" лиц, не рискуя подвергать себя деликатным внутренним процессам. Это меньше контроля доступа и большего доступа; используя защищенный, вы заявляете, что этот метод полезен для детей, но сам по себе он не приносит большого пользы не-детям или будет вреден для класса, если он подвергнут воздействию и будет неправильно использован. Это очень похоже на публикацию знака в вашем переднем дворе, в котором говорится: "Моя дверь заблокирована, и я не буду давать вам ключ, но у всех моих детей есть один". Это даже не половина его, потому что "грабитель" может СДЕЛАТЬ одного из ваших детей и использовать их, чтобы разблокировать дверь.

Общим и общепринятым использованием методов protected для классов Template Method; это абстрактные классы, которые имеют общедоступный скелетный рабочий процесс, но позволяют или требуют расширения определенных частей их функциональных возможностей, чтобы быть полезными. Эти функциональные возможности, как правило, очень слабые и слабые. Шаблон будет раскрывать публичную, не виртуальную "функцию вождения" и несколько ручек для "помощников" в качестве защищенных абстрактных или виртуальных методов. Это позволяет потребителям выводить класс и внедрять помощников.

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

protected также является самым простым способом модульного тестирования внутренних свойств класса. Групповое тестирование - это хорошо, но если вы хотите написать тестовое устройство, которое использует метод, этот метод должен быть доступен извне класса. Частный - это просто не-гость. Внутренняя проблема обычно представляет собой аналогичную проблему. Чтобы вообще провести внутреннее тестирование, они должны быть, по крайней мере, защищены, чтобы вы могли получить класс ДЛЯ ВЫРАЖЕННОЙ ЦЕЛИ, чтобы разоблачить внутренности. В противном случае вам нужно какое-то действительно размышление, чтобы извлечь MethodInfo вашего частного метода и вызвать его (вместе с разрешениями SkipVerification CAS).

Ответ 5

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

Ответ 6

Чрезмерное использование protected может потенциально привести к нарушению Принципа замещения Лискова (L в SOLID) - PDF-ссылка. Принцип гласит, что классы должны быть написаны таким образом, что любой подкласс может быть заменен его базовым классом. Роберт К. Мартин хорошо обсуждает это в Agile Principles, Patterns and Practices на С#. Суть аргумента состоит в том, что подтип является только подтипом, когда он заменяемый для своего базового класса, а не просто имеет отношение IS-A.

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

Это далеко не черное и белое, и нельзя было задать правило одеяла, указывающее, следует ли /t < > t20 > использовать/не использовать. Бывают случаи, когда это действительно необходимо, и есть случаи, когда это не так. Использование суждения в отдельном случае требуется.

Ответ 7

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

С защищенными полями/методами ваш подкласс зависит от внутренней структуры вашего родительского класса, что очень плохо для связи. Это способ сказать: "У меня есть метод/поле 'private', но это нормально для моих подклассов, чтобы использовать его", и хуже "нормально переопределять/изменять его".

На самом деле это не мое мнение, но я понимаю, что некоторые разработчики считают, что модификатор protected уродливый.


Ресурсы:

Ответ 8

Члены

protected приводят к тому, что ваш класс имеет два интерфейса: один для клиентов, которые предпочитают не подклассы, и более крупные для клиентов, которые выбирают подкласс. protected классы одинаковы - они дополняют ваш класс public, который предположительно что-то делает, но они делают это только для определенных клиентов.

Иногда это действительно то, что вы хотите сделать: вы тщательно разработали оба интерфейса, для двух разных вариантов использования. Абстрактные классы могут относиться к этой категории: у вас есть "исполнители", используя интерфейс protected+public и "пользователи", используя только интерфейс public. Там могут быть некоторые полезные функции, которые вы можете предоставить разработчикам, которым не нужны пользователи, и могут быть элементы конфигурации, которые пользователи не затрагивают, но разработчикам необходимо настроить. Выполнение этого с помощью защищенных методов просто избавит вас от определения отдельного интерфейса для некоторого factory, чтобы вернуться к "пользователям". Поэтому я не считаю это вредным, хотя это может считаться немного причудливым, поскольку это не "нормальный" способ определения двух интерфейсов.

Тем не менее, если вы используете protected, это то, что вы фактически не нарушаете инкапсуляцию в ситуации, когда код, который вы хотите его разбить, просто является подклассом. Если что-то "должно" быть private, то сделать это protected нарушает инкапсуляцию, которую вы изначально планировали. Плохой интерфейс по-прежнему является плохим интерфейсом, независимо от того, представлен ли он миру или просто подклассам. В этом отношении есть вероятность, что любой плейс с улицы может подклассифицировать ваш класс. Поэтому даже "просто для подклассов" не очень ограничительный - ваш плохой интерфейс protected находится недалеко от public. Я думаю, что почему люди по умолчанию подозрительно относятся к protected - похоже, что он подметает плохость под ковром, ограничивая, кто его видит, но на самом деле этого не делает.

единственная причина, почему потому что вы можете сделать то же самое вещь в лучшем виде.

Разве этого недостаточно? Делать вещи лучше... лучше; -)

Ответ 9

Одна из причин "Защищено" заключается в том, что может быть полезно, чтобы класс включал в свои контракты вещи, которые относятся к классу, но не обязательно должны относиться к производным классам. В соответствии с принципом замещения Лискова все, что может быть сделано через публичные интерфейсы с объектом типа Q, также должно выполняться с любым объектом, тип которого наследует Q. Таким образом, Q не должен рекламировать какую-либо способность, которая может не присутствовать в некоторых производных Q.

С другой стороны, предположим, что Q обладает некоторой способностью, которая была бы полезна в некоторых производных, но не в других, таких как клонирование. Базовый тип Q может быть клонирован, если выполняются определенные условия, но некоторые подтипы могут не поддерживать клонирование. В этом случае Q должен показывать как "Защищенный" крючки, необходимые для поддержки клонирования. Подтипы, которые могут быть полезны для клонирования, могут использовать эти крючки и выставлять метод клонирования. Те, которые не могут быть клонированы, не будут выставлять крючки.

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

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

Ответ 10

Поскольку protected является общедоступным для своих подклассов, он представляет собой API для подклассов. Это похоже на многие публичные методы для клиента.

Ответ 11

В java защищенный модификатор часто не имеет смысла.

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

Если вы разрабатываете многокомпонентное приложение, вам может понадобиться защищенный модификатор, чтобы beta.Son вызывать конструктор super.class.phather(но в остальном конструктор alpha.Father недоступен). Я буду рассуждать без доказательства того, что разработчики предпочитают однокомпонентные приложения.

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

Ответ 12

Там правило.. "Используйте" Частный ", если у вас нет веской причины не делать этого", Вы должны думать, если кто-то собирается использовать ваши пакеты/классы и решать, что действительно нужно. Я никогда не пользуюсь защитой, если только не собираюсь выпускать lib кому-то другому и только если это необходимо.