JavaRush /Java блог /Java Developer /Принципы инкапсуляции в Java
Автор
Milan Vucic
Репетитор по программированию в Codementor.io

Принципы инкапсуляции в Java

Статья из группы Java Developer
Привет! Сегодняшнюю лекцию посвятим инкапсуляции и начнем ее сразу с примеров :) Перед тобой — привычный автомат с газировкой. У меня к тебе один вопрос: а как он работает? Попробуй ответить подробно: откуда вываливается стакан, как поддерживается температура внутри, где хранится лед, как автомат понимает, какой сироп добавить и т.д. Вероятнее всего, ответов на эти вопросы у тебя нет. Хорошо, возможно не все пользуются такими автоматами, в нынешнее время они не настолько популярны. Попробуем привести другой пример. Что-нибудь, чем ты точно пользуешься много раз каждый день. О, есть идея! Принципы инкапсуляции - 2 Расскажи, как работает поисковик Google. Как именно он ищет информацию по тем словам, которые ты ввел? Почему наверху находятся эти результаты, а не другие? Хотя ты пользуешься гуглом каждый день, скорее всего, ты этого не знаешь. Но это не важно. Ведь тебе и не нужно этого знать. Ты можешь вводить запросы в поисковик не задумываясь, как именно он работает. Ты можешь купить газировку в автомате, не зная как он устроен. Ты можешь водить машину, не вникая в работу двигателя внутреннего сгорания, и вообще не зная физику даже на школьном уровне. Все это возможно благодаря одному из главных принципов объектно-ориентированного программирования — инкапсуляции. Читая разные статьи на эту тему, наверняка ты сталкивался с тем, что в программировании есть два распространенных понятия — инкапсуляция и сокрытие. И под словом «инкапсуляция» авторы понимают то одно, то другое (так уж сложилось). Мы разберем оба термина, чтобы у тебя было полное понимание. Изначальное значение слова «инкапсуляция» в программировании — объединение данных и методов работы с этими данными в одной упаковке («капсуле»). В Java в роли упаковки-капсулы выступает класс. Класс содержит в себе и данные (поля класса), и методы для работы с этими данными. Принципы инкапсуляции - 3 Тебе это кажется очевидным, но в других концепциях программирования все устроено иначе. Например, в функциональном программировании данные строго отделены от операций над ними. В ООП же (объектно-ориентированном программировании) программы состоят из классов-капсул, которые являются одновременно и данными, и функциями для работы с ними. Теперь поговорим о сокрытии. Как же так получается, что мы пользуемся всякими сложными механизмами без понимания, как они устроены и на чем основана их работа? Все просто: их создатели предоставили простой и удобный интерфейс. На автомате с газировкой интерфейс — это кнопки на панели. Нажав одну кнопку, ты выбираешь объем стакана. Нажав вторую, выбираешь сироп. Третья отвечает за добавление льда. И это все, что тебе нужно сделать. Неважно, как именно автомат устроен внутри. Главное — он устроен так, что для получения газировки пользователю нужно нажать три кнопки. То же и с автомобилем. Неважно, что там происходит у него внутри. Главное — при нажатии правой педали автомобиль едет вперед, а при нажатии левой — тормозит. Именно в этом заключается суть сокрытия. Все «внутренности» программы скрываются от пользователя. Для него эта информация является лишней, ненужной. Пользователю необходим конечный результат, а не внутренний процесс. Давай для примера посмотрим на класс Auto:

public class Auto {

   public void gas() {

       /*внутри автомобиля происходят какие-то сложные вещи
       в результате которых он едет вперед*/
   }

   public void brake() {

       /*внутри автомобиля происходят какие-то сложные вещи
       в результате которых он тормозит*/
   }

   public static void main(String[] args) {

       Auto auto = new Auto();

       //Как все выглядит для пользователя

       //нажал одну педаль - поехал
       auto.gas();
      
       //нажал другую педаль - затормозил
       auto.brake();
   }
}
Вот как выглядит сокрытие реализации в Java-программе. Все как в реальной жизни: пользователю предоставлен интерфейс (методы). Если ему нужно, чтобы автомобиль в программе выполнил действие, достаточно вызвать нужный метод. А уж что там происходит внутри этих методов — информация лишняя, главное, чтобы все работало как надо. Здесь мы говорили про сокрытие реализации. Кроме него в Java есть еще сокрытие данных. О нем мы писали в лекции про геттеры и сеттеры, но не будет лишним напомнить. Например, у нас есть класс Cat:

public class Cat {

   public String name;
   public int age;
   public int weight;

   public Cat(String name, int age, int weight) {
       this.name = name;
       this.age = age;
       this.weight = weight;
   }

   public Cat() {
   }

   public void sayMeow() {
       System.out.println("Мяу!");
   }

  
}
Возможно, ты запомнил из прошлой лекции, в чем проблема этого класса? Если нет — давай вспомним. Проблема в том, что его данные (поля) открыты для всех, и другой программист легко может создать в программе безымянного кота с весом 0 и возрастом -1000 лет:

public static void main(String[] args) {

   Cat cat = new Cat();
   cat.name = "";
   cat.age = -1000;
   cat.weight = 0;

}
В такой ситуации можно пристально следить за тем, не создает ли кто-то из твоих коллег объектов с неправильным состоянием, но гораздо лучше было бы исключить саму возможность создавать такие «неправильные объекты». Принципы инкапсуляции - 4 С сокрытием данных нам помогают:
  1. модификаторы доступа (private, protected, package default);
  2. геттеры и сеттеры.
Туда можем, например, заложить проверку, не пытается ли кто-то присвоить коту отрицательное число в качестве возраста. Как мы говорили ранее, авторы разных статей об инкапсуляции имеют в виду либо инкапсуляцию (объединение данных и методов), либо сокрытие, либо и то, и другое. В Java присутствуют оба механизма (в других ООП-языках это не обязательно так), так что последний вариант будет наиболее правильным. Использование инкапсуляции дает нам несколько важных преимуществ:
  1. Контроль за корректным состоянием объекта. Примеры этому были выше: благодаря сеттеру и модификатору private, мы обезопасили нашу программу от котов с весом 0.

  2. Удобство для пользователя за счет интерфейса. Мы оставляем «снаружи» для доступа пользователя только методы. Ему достаточно вызвать их, чтобы получить результат, и совсем не нужно вникать в детали их работы.

  3. Изменения в коде не отражаются на пользователях. Все изменения мы проводим внутри методов. На пользователя это не повлияет: он как писал auto.gas() для газа машины, так и будет писать. А то, что мы поменяли что-то в работе метода gas() для него останется незаметным: он, как и раньше, просто будет получать нужный результат.
Комментарии (97)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Kuttubek7 Уровень 18
15 марта 2024
Заебись обьяснил
Vladislav Gorokhov Уровень 32
11 февраля 2024
Хорошая статья, запомнить бы теорию
LeoAtrox Уровень 25
7 декабря 2023
Стоп, получается сам вызов метода это тоже уже инкапсуляция? Это же слишком обыденно...
chess.rekrut Уровень 25
18 августа 2023
easy
Alexander Rozenberg Уровень 32
25 июля 2023
fine
No Name Уровень 32
25 июня 2023
+ статья в копилке
Ислам Уровень 33
5 июня 2023
Nice
Aquarus Уровень 20
12 января 2023
""" То же и с автомобилем. Неважно, что там происходит у него внутри. Главное — при нажатии правой педали автомобиль едет вперед, а при нажатии левойтормозит. """ Автор видать на картинге часто гоняет.... (:
partiec Уровень 33
27 декабря 2022
В книгах советских времен можно вычитать типа: - Мы с другом ходили на завод пить газировку из автомата. или - Мой дед - литейщик, мог выпить за раз литр ситро! статья в этом стиле 😀👍
Blynchik Уровень 51
16 мая 2022
где-то читал, для чего нужны капсулы из первой картинки