Подтвердить что ты не робот

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

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

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!!
    }
}

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

4b9b3361

Ответ 1

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

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

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

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

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

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

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

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

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

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

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

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

Ответ 5

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

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

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

Ответ 6

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

Ответ 7

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

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

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

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

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

Ответ 8

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

Ответ 9

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

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

Ответ 10

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

Ответ 11

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

Ответ 12

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

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

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