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

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

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

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

  1. Что защищают частные переменные?

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

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

197 голосов | спросил mwallace 10 AMpTue, 10 Apr 2012 09:31:08 +040031Tuesday 2012, 09:31:08

14 ответов


285

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

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

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

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

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

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

ответил tdammers 10 AMpTue, 10 Apr 2012 09:48:09 +040048Tuesday 2012, 09:48:09
108

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

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

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

ответил Oleksi 10 AMpTue, 10 Apr 2012 09:41:38 +040041Tuesday 2012, 09:41:38
23

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

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

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

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

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

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

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

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

ответил Frank 10 AMpTue, 10 Apr 2012 09:48:22 +040048Tuesday 2012, 09:48:22
5

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

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

function SomeObject () {
    this.a = 2; //Общедоступная (ну, фактически защищенная) переменная

    this.showA = function () {
        оповещения (this.a);
    }
}

//Некоторые строки вниз ...

var obj = new SomeObject ();
obj.a = 3;
obj.showA (); //Будет предупреждать 3. О, о!

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

function SomeObject () {
    var a = 2; //Частная переменная

    this.showA = function () {
        оповещения (а);
    }
}

//Некоторые строки вниз ...

var obj = new SomeObject ();
obj.a = 3;
obj.showA (); //Будет предупреждать 2

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

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

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

ответил Jeffrey Sweeney 10 AMpTue, 10 Apr 2012 09:52:30 +040052Tuesday 2012, 09:52:30
4

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

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

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

ответил Karl Bielefeldt 10 PMpTue, 10 Apr 2012 19:53:51 +040053Tuesday 2012, 19:53:51
3

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

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

ответил Karl Bielefeldt 10 PMpTue, 10 Apr 2012 19:53:51 +040053Tuesday 2012, 19:53:51
2
  • Что защищают личные переменные?

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

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

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

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

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

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

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

ответил Erik Reppen 10 PMpTue, 10 Apr 2012 20:47:52 +040047Tuesday 2012, 20:47:52
2

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

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

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

ответил KeithS 10 PMpTue, 10 Apr 2012 18:42:52 +040042Tuesday 2012, 18:42:52
2

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

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

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

ответил jmoreno 10 PMpTue, 10 Apr 2012 19:41:38 +040041Tuesday 2012, 19:41:38
1

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

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

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

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

ответил rajNaveen 10 AMpTue, 10 Apr 2012 09:52:06 +040052Tuesday 2012, 09:52:06
1

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

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

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

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

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

ответил Patrick 17 PMpTue, 17 Apr 2012 23:27:13 +040027Tuesday 2012, 23:27:13
1

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

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

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

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

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

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

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

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

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

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

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

Теперь решить частную и защищенную проблему - настоящая проблема.

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

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

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

ответил Aquarius Power 17 J0000006Europe/Moscow 2016, 05:48:24
0

imo @tdammers неверен и фактически вводит в заблуждение.

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

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

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

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

ответил wolfdawn 3 Maypm17 2017, 21:05:02
-4

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

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

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

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

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

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

ответил DeveloperArnab 27 J0000006Europe/Moscow 2013, 17:08:24

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132