использование частного ключевого слова

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

public class BadOO {
    public int size;

    public int weight;
    ...
}

public class ExploitBadOO {
    public static void main (String [] args) {
        BadOO b = new BadOO();
        b.size = -5; // Legal but bad!!
    }
}

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

20
задан Austin Hyde 19 October 2010 в 21:19
поделиться

12 ответов

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

Например, один программист пишет общедоступные методы получения и установки вокруг частной переменной-члена. Три месяца спустя ему нужно убедиться, что переменная никогда не была «установлена» в нуль. Он добавляет проверку в методе "setFoo (...)", и все попытки установить переменную затем будут проверяться на "установку ее в нуль". Дело закрыто, причем без особых усилий.

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

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

Называйте это как хотите, но использование общедоступных методов get и set вокруг частной переменной-члена является защитным программированием, которое возникло благодаря многолетнему (то есть десятилетиям) опыта.

17
ответ дан 29 November 2019 в 23:16
поделиться

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

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

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

Вместо этого, если бы у вас был метод набора, вы могли бы расширить его, чтобы сказать

void SetSize(int newSize)
{ 
   size = newSize;
   DoCalculation;
}

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

4
ответ дан 29 November 2019 в 23:16
поделиться

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

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

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

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

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

1
ответ дан 29 November 2019 в 23:16
поделиться

Программисты на C # используют это в равной степени, а может быть, и чаще, чем я вижу в Java. C # называет это свойствами, тогда как в Java - аксессорами / мутаторами

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

0
ответ дан 29 November 2019 в 23:16
поделиться

Это действительно используется, чтобы скрыть внутреннюю реализацию. Это также помогает предоставить дополнительную логику для ваших переменных. Скажем, вам нужно убедиться, что значение, переданное для переменной, не должно быть 0 / null, вы можете предоставить эту логику в методе set. Точно так же вы можете предоставить некоторую логику при получении значения, скажем, у вас есть объектная переменная, которая не инициализирована, и вы обращаетесь к этому объекту, в этом случае вы можете предоставить логику для нулевой проверки для этого объекта и всегда возвращать объект.

1
ответ дан 29 November 2019 в 23:16
поделиться

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

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

22
ответ дан 29 November 2019 в 23:16
поделиться

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

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

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

6
ответ дан 29 November 2019 в 23:16
поделиться

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

Ваш вопрос рассматривается в пунктах 13 и 14 этой книги:

  • Правило 13: Минимизируйте доступность классов и членов
  • Правило 14: В общедоступных классах используйте методы доступа, а не общедоступные поля
2
ответ дан 29 November 2019 в 23:16
поделиться

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

1
ответ дан 29 November 2019 в 23:16
поделиться

Хорошо. Здесь мы говорим об объектах. Объекты реального мира. Если они не являются частными, пользователю вашего класса разрешено изменить. Что делать, если для класса Circle и для атрибута / свойства радиуса класса Circle пользователь устанавливает значение как «0». Для Круга с радиусом «0» не имеет смысла.Вы можете избежать таких ошибок, если сделаете свои атрибуты частными и дадите метод установки и в котором и выкинете исключение / ошибку (инструктируя пользователя), что не разрешено создавать круг с radisu как '0'. По сути, объекты, созданные вне вашего класса, предназначены для того, чтобы существовать так, как вы хотели, чтобы они существовали. Это один из способов добиться этого.

0
ответ дан 29 November 2019 в 23:16
поделиться

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

0
ответ дан 29 November 2019 в 23:16
поделиться

Это зависит от того, кто имеет доступ к этим публичным переменным. Скорее всего, только люди внутри вашей компании/команды. Тогда тривиально рефакторить их в геттеры/сеттеры, когда это необходимо. Я считаю, что в этом случае лучше оставить переменные открытыми, если только вы не вынуждены следовать конвенции java bean.

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

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

-4
ответ дан 29 November 2019 в 23:16
поделиться
Другие вопросы по тегам:

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