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

Инкапсуляция Java

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

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

4b9b3361

Ответ 1

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

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

То есть,

private int x;

public int getInt(String password){
 if(password.equals("RealPassword")){
   return x;
  }
}

И то же самое для сеттеров.

Ответ 2

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

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

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

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

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

Есть несколько причин, почему вы можете захотеть инкапсулировать доступ к вашим полям. Джошуа Блох в своей книге " Эффективная Java" в пункте 14 "Минимизируйте доступность классов и членов" упоминает несколько веских причин, которые я цитирую здесь:

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

Однако инкапсуляция - это больше, чем скрытие полей. В Java вы можете скрыть целые классы, скрывая детали реализации всего API. Подумайте, например, о методе Arrays.asList(). Он возвращает реализацию List, но вам все равно, какая реализация, если она удовлетворяет интерфейсу List, верно? Реализация может быть изменена в будущем, не затрагивая пользователей метода.

Красота инкапсуляции

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

Подумайте, например, об уровне абстракции в концепции автомобиля. Автомобиль сложен в своей внутренней реализации. У них есть несколько подсистем, таких как система трансмиссии, тормозная система, топливная система и т.д.

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

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

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

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

Я действительно рекомендую вам прочитать статью Алана Снайдера " Инкапсуляция и наследование в объектно-ориентированных языках программирования". Эта ссылка указывает на оригинальную статью о ACM, но я уверен, что вы сможете найти PDF-копию через Google.

Ответ 3

Данные безопасны, потому что вы можете использовать дополнительную логику в вашем методе получения/установки, и невозможно изменить значения вашей переменной. Представьте, что ваш код не работал с нулевой переменной, поэтому в вашем установщике вы можете проверить нулевые значения и назначить значение по умолчанию! = Null. Таким образом, ваш код все еще работает, независимо от того, пытается ли кто-то установить для вашей переменной значение null.

Ответ 4

Мой вопрос: если мы можем получить доступ к переменным (данным) через геттеры и сеттеры, почему данные скрыты или безопасны?

Вы можете заключить логику в геттеры/сеттеры. Например,

public void setAge(int age) {
    if (age < 0) {
        this.age = 0;
    }
    else {
        this.age = age;
    }
}

Ответ 5

Продолжая ответ Jigar: Есть несколько вещей, которые попадают под инкапсуляцию.

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

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

Ответ 6

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

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

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

почему данные скрыты или безопасны

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

Ответ 7

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

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

Ответ 8

Мне нравится объяснение, принимая во внимание темы. Если вы сделали свои поля общедоступными, как ваш экземпляр узнает, когда определенный поток изменил одно из своих полей?

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

Ответ 9

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

Методы правильно названы с глаголом в начале. Например: getName(), setName(), isDying(). Что может помочь прочитать код!