Частный и защищенный - видимость Хорошая практика

Я искал, и я знаю теоретическую разницу.

  • public. Любой класс/функция может получить доступ к методу/свойству.
  • protected. Только этот класс и любые подклассы могут получить доступ к методу/свойству.
  • private. Только этот класс может получить доступ к методу/свойству. Он даже не будет унаследован.

Что все хорошо и хорошо, вопрос в том, какова практическая разница между ними? Когда вы будете использовать private и когда вы будете использовать protected? Существует ли стандартная или приемлемая хорошая практика над этим?

До сих пор, чтобы сохранить концепцию наследования и полиморфизма, я использую public для чего-либо, к которому следует обращаться извне (например, конструкторы и функции основного класса), и protected для внутренних методов (логика, помощник методы и т.д.). Я на правильном пути?

(Обратите внимание, что этот вопрос для меня, но и для будущей справки, поскольку я не видел такого вопроса, как этот SO).

Ответ 1

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

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

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

Ответ 2

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

Старая мудрость

"отметьте это как частное, если у вас нет веских причин не делать этого"

Это имело смысл в те дни, когда оно было написано, до того, как открытый исходный код доминировал в пространстве библиотеки для разработчиков и в зависимости от VCS/mgmt. благодаря сотрудничеству с Github, Maven и т.д. стали сотрудничать друг с другом. Тогда еще можно было заработать, ограничивая способ использования библиотеки. Я провел, вероятно, первые 8 или 9 лет моей карьеры, строго придерживаясь этой "лучшей практики".

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

Вы когда-нибудь:

  • Были разочарованы, удивлены или обижены библиотекой и т.д., В которой была ошибка, которая могла быть исправлена с помощью наследования и нескольких строк кода, но из-за методов private/final классы были вынуждены ждать официального патча, который может никогда не появиться? Я имею.
  • Хотели использовать библиотеку для немного другого варианта использования, чем предполагали авторы, но не смогли этого сделать из-за закрытых/финальных методов и классов? Я имею.
  • Были разочарованы, удивлены или обижены библиотекой и т.д., Которая была чрезмерно разрешительной в ее расширяемости? Я не.

Вот три самых больших объяснения, которые я слышал о пометке методов private по умолчанию:

Рационализация № 1: это небезопасно и нет причин переопределять конкретный метод

Я не могу сосчитать, сколько раз я ошибался в том, будет ли когда-либо необходимость переопределять определенный метод, который я написал. Проработав несколько популярных библиотек с открытым исходным кодом, я с трудом узнал истинную стоимость маркировки вещей частными. Это часто исключает единственное практическое решение непредвиденных проблем или вариантов использования. И наоборот, за 16+ годы профессионального развития я никогда не сожалел о том, что помечал метод, защищенный вместо частного, по причинам, связанным с безопасностью API. Когда разработчик решает расширить класс и переопределить метод, он сознательно говорит: "Я знаю, что я делаю". и ради производительности этого должно быть достаточно. период. Если это опасно, отметьте это в классе/методе Javadocs, а не просто слепо захлопните дверь.

Методы маркировки, защищенные по умолчанию, - это смягчение одной из основных проблем в разработке современных ЕО: провал воображения.

Рационализация № 2: поддерживает чистоту общедоступного API/Javadocs

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

Рационализация № 3: Мое программное обеспечение является коммерческим, и я должен ограничить его использование.

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

Никогда не говори никогда

Я не говорю, никогда не отмечайте методы как частные. Я говорю, что лучшее эмпирическое правило - "делать методы защищенными, если нет веских причин не делать этого".

Этот совет лучше всего подходит для тех, кто работает над библиотеками или крупномасштабными проектами, разбитыми на модули. Для небольших или более монолитных проектов это не имеет большого значения, так как вы все равно контролируете весь код, и легко изменить уровень доступа к коду, если/когда вам это нужно. Хотя и тогда я бы дал тот же совет :-)

Ответ 3

Недавно я прочитал статью, в которой говорилось о максимально возможном блокировании каждого класса. Сделайте все окончательным и конфиденциальным, если у вас нет немедленной необходимости раскрывать некоторые данные или функциональные возможности для внешнего мира. Всегда легко расширить область действия, которая будет более разрешена позже, но не наоборот. Сначала рассмотрим возможность сделать как можно больше вещей final, что облегчит выбор между private и protected.

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

Теперь, если вы остаетесь с последним классом, сделайте все частным, если что-то абсолютно не требуется миру - сделайте это общедоступным.

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

Отказ от ответственности: я не программирую много в Java:)

Ответ 4

Остановить использование личных полей!!!

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

Являются ли частные поля хорошими в принципе? Да. Но говоря, что золотое правило делает все частным, когда вы не уверены, что определенно ошибочен! Вы не увидите проблему, пока не столкнетесь с ней. По-моему, вы должны отмечать поля как защищенные, если вы не уверены,.

Есть два случая, по которым вы хотите расширить класс:

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

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

Рассмотрим простую библиотеку, которая моделирует автомобили:

class Car {
    private screw;
    public assembleCar() {
       screw.install();
    };
    private putScrewsTogether() {
       ...
    };
}

Автор библиотеки подумал: нет ли причины, по которой пользователи моей библиотеки должны иметь доступ к деталям реализации assembleCar() правильно? Отметьте винт как закрытый.

Ну, автор ошибается. Если вы хотите изменить только метод assembleCar(), не копируя весь класс в свой пакет, вам не повезло. Вы должны переписать свое собственное поле screw. Скажем, этот автомобиль использует дюжину винтов, и каждый из них включает в себя некоторый нетривиальный код инициализации в разных частных методах, и эти винты все маркированы частными. На данный момент он начинает сосать.

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

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

Я очень поддерживаю ответ Ника.

Ответ 5

Когда вы будете использовать private и когда вы будете использовать protected?

Частное наследование можно рассматривать как Реализовано в терминах отношения, а не с отношением IS-A. Проще говоря, внешний интерфейс наследующего класса не имеет (видимого) отношения к унаследованному классу, он использует наследование private только для реализации аналогичной функциональности, которую предоставляет базовый класс.

В отличие от Private Inheritance, Защищенное наследование является ограниченной формой Inheritance, где класс класса IS-A класса Base и он хочет ограничить доступ полученных членов только к производному классу.

Ответ 6

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