Зачем нам нужны частные переменные?


210

Зачем нам нужны закрытые переменные в классах?

В каждой книге по программированию, которую я прочитал, говорится, что это частная переменная, именно так вы ее определяете, но на этом остановимся.

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

  1. Что помогают предотвратить частные переменные?

  2. Как вы решаете, должна ли конкретная собственность быть частной или нет? Если по умолчанию каждое поле ДОЛЖНО быть приватным, то почему в классе есть открытые члены данных?

  3. При каких обстоятельствах переменная должна быть опубликована?


9
Ваш вопрос звучит очень не зависимо от языка, но вы пометили его как java и c ++. Если вас интересуют перспективы извне этих двух языков, вам, вероятно, следует сказать об этом.
Джеймс

8
Для записи, создание частного метода не увеличивает «безопасность». Другие части вашего приложения могут по-прежнему получать доступ к закрытым членам, используя рефлексию.
КБА

3
Использование и различие частных и общедоступных переменных и то, почему мы их имеем, может быть понято только в контексте общих объектно-ориентированных принципов. Это не может быть понято отдельно. Вы, вероятно, должны смотреть на это с этой точки зрения, все может стать яснее.
Назар Мерза

1
возможный дубликат « Когда оправданы
добытчики

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

Ответы:


307

Это не столько вопрос доверия, сколько вопрос управления сложностью.

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

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

Другое преимущество связано с понятием «сцепление». Открытый член mкласса, Aкоторый используется другим классом, Bвводит зависимость: если вы изменяете min A, вы также должны проверить использование min B. Хуже того, ничто в классе не Aговорит вам, где mиспользуется, поэтому вам снова придется искать по всей базе кода; если вы пишете библиотеку, вам даже нужно убедиться, что код за пределамиваш проект не ломается из-за ваших изменений. На практике библиотеки склонны придерживаться своих оригинальных сигнатур методов как можно дольше, независимо от того, насколько они болезненны, а затем вводить блок критических изменений при обновлении основной версии. В отличие от закрытых членов, вы можете сразу исключить зависимости - к ним нельзя получить доступ извне, поэтому все зависимости содержатся внутри класса.

В этом контексте «другие программисты» включают ваше будущее и прошлое. Скорее всего , вы знаете , в настоящее время , что вы не должны делать эту вещь X с переменной Y, но вы обязаны забыть три месяца вниз по дороге , когда клиент срочно нуждается в вас , чтобы реализовать некоторые функции, и вы удивляетесь , почему делают X - брейки У неясных способов.

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


24
+1 за суть проблемы, хотя лично я нашел, что мой код легче поддерживать, когда я перестал проходить через обручи, просто чтобы гарантировать, что часто используемая переменная остается приватной. Конечно, в будущем может появиться ошибка, но для просеивания требуется на 60 строк кода меньше, а для загрузки
Джеффри Суини,

48
Священный Грааль современных вычислений сдерживает сложность.

1
Мне всегда нравится говорить, что часть отладки заключается не только в том, чтобы «прямо что-то пошло не так», но и в обходном процессе выяснения «что-то пошло не так» и сосредоточении моего исследования на том, что осталось. Если я смогу заставить компилятор помочь мне с такими инструментами, как частные переменные, определить «что не могло произойти», это сэкономит мне массу времени. Только в тех редких случаях, когда я доказываю, что то, что пошло не так, не могло произойти, мне приходится копаться в более пугающих предположениях, таких как, возможно, переполнение буфера, перезаписывающее мои личные данные.
Cort Ammon

2
Именно это. Когда люди слышат «сокрытие информации», они думают, что им следует использовать личные переменные для таких вещей, как ключи шифрования, учетные данные базы данных и т. Д.
Уэйн Вернер

2
@AdamZerner см. «Говори, а не спрашивай» ( martinfowler.com/bliki/TellDontAsk.html ) о том, чтобы в первую очередь получить геттеры / сеттеры - но в противном случае да, потому что вы должны иметь возможность в любое время изменить внутреннее представление значения ты хочешь. Как всегда, есть исключения ... (например, DTO)
doubleYou

111

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

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

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


24
ИМО также касается общения между автором библиотеки и потребителем библиотеки. Публичный интерфейс похож на «используй это», а приватные - на «не используй это», за исключением того, что в Java вы действительно не можете использовать его случайно, если сделаете его закрытым, чтобы он был безопаснее и понятнее.
Chakrit

5
@chakrit и другие: обратите внимание, что те, кто действительно хочет использовать ваши личные поля и методы, могут это сделать (через рефлексию). privateменьше, чем «не предназначен в первую очередь для безопасности», он не обеспечивает никакой «безопасности», о которой можно говорить. Это просто сильный намек (доставляется через компилятор), чтобы не получить к нему доступ.

@delnan обратите внимание на фразу «случайно», да, может быть, я должен быть более ясным по этому поводу.
Chakrit

@chakrit Да, я не хотел сказать, что ты был неправ. Я просто хотел продвигать этот момент.

1
@delnan: Частные поля на некоторых языках обеспечивают определенные формы безопасности. Например, см. Ответ Эрика Липперта на вопрос: служат ли уровни доступа и модификаторы (закрытые, закрытые и т. Д.) Для целей безопасности в C #? ,
Брайан

25

Ключевое слово здесь - Инкапсуляция . В ООП вы хотите использовать закрытые переменные для обеспечения правильной инкапсуляции ваших объектов / классов.

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

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

  2. В традиционных языках, таких как C ++ или Java, вы обычно делаете все приватным и доступным только для соответствующих методов получения и установки. Не нужно много решать на самом деле.

  3. Иногда, например в структуре C ++ класс нужен только как способ группировки нескольких вещей. Например, рассмотрим класс Vector , который имеет xи с yтолько атрибут. В этих случаях вы можете разрешить прямой доступ к этим атрибутам, объявив их открытыми. В частности, вам не нужно заботиться о том, что какой-то код снаружи изменяет объект вашего класса, напрямую записывая новые значения в xили y.

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

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

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


1
+1 «Хотя другие программисты не хотят вас достать, они взаимодействуют с вашим кодом». Программисты, использующие ваш код, по своей сути не являются злом. Используя закрытые переменные, вы гарантируете, что они (и вы, в будущем) не пострадают от использования кода. Это также поможет вам разработать лучший API и задокументировать его.
szalski

7

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

Например, прототипные языки, такие как Javascript, могут позволять пользователям накладывать переменные так, как они считают нужным:

function SomeObject() {
    this.a = 2; //Public (well, actually protected) variable

    this.showA = function() {
        alert(this.a);
    }
}

//Some lines down...

var obj = new SomeObject();
obj.a = 3;
obj.showA(); //Will alert 3. Uh oh!

Если бы эта переменная была закрытой, ее нельзя было бы изменить извне:

function SomeObject() {
    var a = 2; //Private variable

    this.showA = function() {
        alert(a);
    }
}

//Some lines down...

var obj = new SomeObject();
obj.a = 3;
obj.showA(); //Will alert 2

Тем не менее, не все переменные должны быть закрытыми, а чрезмерное использование частных переменных может на самом деле сделать код более громоздким. Тривиальные поля, которые не оказывают серьезного влияния на объект, не нуждаются get()и в set()методах.

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

Открытые переменные следует использовать, когда объект / функция будет обращаться к другим объектам / функциям, поскольку, как правило, закрытые переменные не могут этого делать. У вас может быть от нескольких до нескольких открытых переменных, и их использование не является плохим, если они используются правильно.


Непонятно, почему предупреждение 3 было бы "ах!" в этом случае. Может быть, это то, что программист хотел, чтобы это произошло.
иммибис

@immibis Возможно, и, возможно, я должен был уточнить в ответе. Но доступ к свойствам может открыть дверь для нарушения некоторых принципов ООП, таких как принцип открытого-закрытого или LoD, поскольку вы потенциально можете раскрыть детали реализации. Конечно, с вашей точки зрения, это зависит от того, что именно является собственностью. Большинство языков используют объекты в качестве ссылок, и когда ссылки на объекты передаются, и коллеги-разработчики незаметно меняют свойства, это может быть ОЧЕНЬ трудно отладить. IMO гораздо проще и расширяемее работать с методами, если у вас есть экземпляр класса.
Джеффри Суини

7

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

Дело не в том, что языки без конфиденциальности делают такой дизайн невозможным, просто менее вероятным. Вместо того, чтобы предлагать что-то наподобие foo.getBar(), люди склонны думать, что геттер не нужен, потому что его легче написать foo.bar, но тогда это решение не пересматривается, когда вы в итоге получаете более длинные чудовища, подобные obj.container[baz].foo.bar. Программисты, которые никогда не работали на более строгом языке, могут даже не видеть, что с этим не так.

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


3

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

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


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

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

1
@DavidK Может быть, то, что bbb хотел сказать, это то, что «закрытые переменные не позволяют другим входить и без разбора изменять состояние объекта». Публичные методы могут изменять частное состояние объекта, но только способами, которые необходимы и согласованы для функционирования объекта.
Макс Нанаси

@Max Nanasy: Да, можно контролировать, как изменяется состояние, когда в общедоступном интерфейсе предлагаются только методы. Например, между членами могут быть отношения, которые должны быть выполнены для того, чтобы объект был «самосогласованным», и вы могли бы позволить самосогласованному состоянию измениться только на другое самосогласованное состояние. Если все эти переменные общедоступны, то вы не можете применить это. Но также могут быть объекты, в которых вы не хотите вносить какие-либо изменения, поэтому важно прояснить, о какой из этих вещей мы говорим.
Дэвид К

2
  • Что помогают предотвратить частные переменные?

Речь идет о том, чтобы прояснить, какие свойства и методы являются интерфейсом, а какие на самом деле являются основными функциями. Открытые методы / свойства относятся к другому коду, часто к коду другого разработчика, использующего ваши объекты. Я никогда не работал над командами из 100+ над одним и тем же проектом, но, по моему опыту, команды из 3-5 человек и до 20 других разработчиков используют вещи, которые я написал, другие проблемы кажутся глупыми.

Примечание: я в первую очередь разработчик JavaScript. Я обычно не беспокоюсь о том, что другие разработчики просматривают мой код, и я полностью осознаю, что они могут просто переопределить мои материалы в любое время. Я предполагаю, что они достаточно компетентны, чтобы знать, что они делают в первую очередь. Если нет, то вряд ли я буду работать в команде, которая не использует систему контроля версий.

  • Как вы решаете, должен ли определенный набор свойств быть закрытым или нет? Если по умолчанию каждое поле ДОЛЖНО быть приватным, то почему в классе есть открытые члены данных?

Раньше я думал, что глупо помещать методы получения и установки в частные свойства, когда вы на самом деле не выполняли какую-либо проверку или другую специальную обработку свойства, которое нужно установить. Я до сих пор не думаю, что это всегда необходимо, но когда вы имеете дело с крупномасштабной, высокой сложностью, но, самое главное, с множеством других разработчиков, полагающихся на то, что ваши объекты ведут себя согласованно, может быть полезно сделать что-то в последовательный и единый способ. Когда люди видят вызванные методы getThatиsetThatОни точно знают, каковы намерения, и могут написать свои объекты, чтобы взаимодействовать с вашими, ожидая, что они всегда будут получать помидоры, а не томахто. Если они этого не делают, они знают, что ваш объект дает им то, чего он, вероятно, не должен, что означает, что он позволяет другому объекту делать что-то с этими данными, чего он, вероятно, не должен. Вы можете контролировать это по мере необходимости.

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

  • При каких обстоятельствах переменная должна быть опубликована?

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


ИМХО, нет ничего особенно плохого в том, чтобы иметь публичный класс, единственная цель которого - выставить публичные переменные. В самом деле, виртуальная машина имеет ряд встроенных классов для этой цели: int[], double[], Object[]и т.д. Следует, однако, быть очень осторожным о том , как один выставляют экземпляры такого класса. Смысл void CopyLocationTo(Point p);[принятия a Pointот вызывающего абонента] более понятен Point location(), так как неясно, какое влияние Point pt = foo.location(); pt.x ++;окажет местоположение foo.
суперкат

2

Смотрите этот пост на мой связанный вопрос о SO .

Суть в том, что область видимости переменной позволяет вам показать потребителям вашего кода, с чем им следует и не следует связываться. Закрытая переменная может содержать данные, которые были «проверены» с использованием установщика свойств или метода обработки, чтобы гарантировать, что весь объект находится в согласованном состоянии. Непосредственное изменение значения закрытой переменной может привести к тому, что объект станет несовместимым. Делая это частным, кто-то должен по-настоящему усердно работать и иметь действительно высокие разрешения времени выполнения, чтобы изменить его.

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


2

Я собираюсь поговорить о значении инкапсуляции с другой точки зрения на реальном примере. Некоторое время назад (в начале 80-х) для Radio Shack Color Computer была написана игра под названием Dungeons of Daggorath. Несколько лет назад Ричард Ханерлах портировал его из списка сборщика бумаги на C / C ++ ( http://mspencer.net/daggorath/dodpcp.html ). Некоторое время спустя я получил код и начал перефакторинг, чтобы улучшить инкапсуляцию ( http://dbp-consulting.com/stuff/ ).

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

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

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

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


Жесткий баланс между «свободой наших пользователей lib» и «меньшими проблемами для нас». Я начинаю верить, что инкапсуляция лучше в том смысле, что я буду предотвращать ошибки в моем собственном кодировании и помогу конечным пользователям также предотвращать ошибки. Но отсутствие свободы может просто убрать их и искать альтернативы ... Может быть, кодирование еще не используется, но предусмотренные функциональные возможности через публичные методы могут помочь сбалансировать это, но требуют больше времени.
Водолей Сила

Жаль, что переработанная версия не на github ....
jmoreno

2

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

Рассмотрим частные константы - они не должны содержать секретных значений (они должны храниться в другом месте), их нельзя изменить, их не нужно передавать в ваш класс (в противном случае они должны быть открытыми). Единственное возможное использование для них - в качестве констант в ДРУГИХ классах. Но если вы сделаете это, эти классы теперь зависят от вашего класса, чтобы выполнять работу, не связанную с вашим классом. Если вы измените константу, другие классы могут сломаться. Это плохо с обеих сторон - как писатель вашего класса, вы хотите, чтобы свобода изменилась как можно больше, и не хотите беспокоиться о вещах вне вашего контроля. Потребитель вашего класса хочет иметь возможность зависеть от раскрытых деталей вашего класса, не беспокоясь о том, что вы измените его и нарушите его код.

Потребитель вашего класса хочет знать все, что необходимо для ВЗАИМОДЕЙСТВИЯ с вашим классом, и не хочет знать что-либо о вашем классе, что не меняет его поведения: это бесполезные мелочи. Если вы использовали язык с отражением, как часто вы использовали его, чтобы узнать не о том, как какой-то класс делает что-то или где он неожиданно выдает исключение, а просто о названии приватных полей и методов? Я держу пари никогда. Потому что вы не пользуетесь этими знаниями.


1

Концепция ООП имеет наследование имеет одну из своих функций (Java или C ++). Так что, если мы собираемся наследовать (то есть мы собираемся получить доступ к переменным унаследованного класса), есть возможность повлиять на эти переменные. Таким образом, мы должны решить, могут ли переменные быть изменены или нет.

Только для этой цели мы используем модификаторы доступа в ООП. Один из модификаторов является закрытым, то есть доступ к нему может получить только этот класс. Любой другой класс не может влиять на эти переменные.

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

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


1

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

Но с другой стороны, то, что в основном игнорируется другими, касается защищенных полей.

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

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

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

Гибкость против неприятностей, плюсы и минусы:

Объекты, созданные вашим кодом в классе vanilla с защищенными полями, являются безопасными и являются вашей исключительной ответственностью.

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

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

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

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

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

Когда использовать защищенный?

Каждый раз, когда вы понимаете, что поле может быть очень гибким, оно должно быть закодировано как защищенное. Эта гибкость заключается в следующем: от обнуления (когда ноль всегда проверяется и распознается как допустимое состояние без исключений) до наличия ограничений перед использованием вашим классом ex. > = 0, <100 и т. Д. И автоматически исправляется для значений превышения / недостаточности потока, выдавая самое большее предупреждающее сообщение.

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


-1

imo @tdammers не прав и на самом деле вводит в заблуждение.

Частные переменные существуют, чтобы скрыть детали реализации. Ваш класс Aможет использовать arrayдля хранения результатов. Завтра вы можете использовать treeили priority queueвместо. Все пользователи вашего класса нуждаются в способе ввода баллов и имен addScore()и способе определить, кто входит в десятку лучших getTop(n).

Им не нужен доступ к базовой структуре данных. Звучит здорово? Ну, есть несколько предостережений.

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

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


-1
  • Доступ к переменной означает доступ к ее значению при запуске программы, а частная переменная защищает ее значение при выполнении кода.
  • Смысл так называемого «сокрытия данных» состоит в том, чтобы скрыть внутренние данные от других классов, которые используют этот класс. Этим другим классам следует обращаться к поведению только путем вызова методов класса, а не путем непосредственного изменения значений переменных.
  • Сделав переменную закрытым элементом данных, вы можете легче гарантировать, что значение никогда не будет изменяться или изменяться. С другой стороны, если переменная общедоступна, другой класс может изменить или изменить значение, что может привести к сбою других частей кода.

1
кажется, это не дает ничего существенного по сравнению с замечаниями, сделанными и объясненными в предыдущих 17 ответах
комнат

-4

Сначала вы должны понять концепцию объектно-ориентированного программирования. Имеет абстракцию, инкапсуляцию и т. Д.

Абстракция - Вы получаете представление о логике без необходимости подчеркивать детали реализации.

Инкапсуляция - Вы не можете видеть подчеркивание реализации объекта. Только вы можете видеть открытый интерфейс объекта.

Теперь в конкретной реализации с одной из объектно-ориентированных программ, таких как C #, Java, C ++, вы можете реализовать эти концепции.

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

public - это интерфейс, с помощью которого можно использовать ваш объект.


1
защищенный - напрямую доступен для подклассов (extenders) (java).
Водолей Сила
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.