User Professor Hans Noodles
Professor Hans Noodles
41 уровень

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

Статья из группы Java Developer
Привет! Сегодняшнюю лекцию посвятим инкапсуляции и начнем ее сразу с примеров :) Принципы инкапсуляции - 1Перед тобой — привычный автомат с газировкой. У меня к тебе один вопрос: а как он работает? Попробуй ответить подробно: откуда вываливается стакан, как поддерживается температура внутри, где хранится лед, как автомат понимает, какой сироп добавить и т.д. Вероятнее всего, ответов на эти вопросы у тебя нет. Хорошо, возможно не все пользуются такими автоматами, в нынешнее время они не настолько популярны. Попробуем привести другой пример. Что-нибудь, чем ты точно пользуешься много раз каждый день. О, есть идея! Принципы инкапсуляции - 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() для него останется незаметным: он, как и раньше, просто будет получать нужный результат.
Комментарии (71)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Blynchik Уровень 23, Чебоксары, Россия
16 мая 2022
где-то читал, для чего нужны капсулы из первой картинки
Aleksei Reinsalu Уровень 19, Таллинн, Эстония
28 ноября 2021
Ок. Либо вообще любое сокрытие методов или данных, либо соединяем данные и методы для этих данных в одном флаконе. Какое умное слово Инкапсуляция однако..
Sergey Kornilov Уровень 38, Petropavlovsk, Казахстан
24 октября 2021
Эту лекцию уже давали ранее.
Nadezhda Goncharova Уровень 35
31 августа 2021
На эту лекцию закидывает ссылками с разных уровней :)
Лизунов Сергей Уровень 41, Пенза, Россия
28 мая 2021
Только я попытался прочитать название на баночке с капсулами?
Станислав Уровень 13, Санкт-Петербург, Россия
18 марта 2021
Получается Инкапсуляция это тот факт, что мы в классе описываем и его переменные и его методы, а Сокрытие это возможность их защитить значением private?
BotGabe Уровень 20, Москва, Россия
5 марта 2021
Спасибо профессор Фарнсворт
🦔 Виктор Уровень 20, Москва, Россия Expert
8 декабря 2020
Что первая, что вторая (эта) статья, как будто не дописаны и брошены на самом интересном месте. Либо мне не хватает какого-то резюмирования в конце, а-ля «мораль сей басни такова: инкапсуляция — это..., а сокрытие — это...». Эх, мне кажется, что всё было бы гораздо понятнее с таким подытоживанием в конце: 1. Сокрытие реализации — это механизм для ограничения доступа к некоторым компонентам объекта. Сокрытие данных означает сокрытие от пользователя несущественных деталей и отображение ему только соответствующих данных. Сокрытие данных достигается посредством модификаторов доступа (private, public, protected, default-package), каждый из которых определяет свой уровень доступности. 2. Инкапсуляция — это объединение данных и методов работы с этими данными в одной упаковке («капсуле»). В Java в роли упаковки-капсулы выступает класс. Класс содержит в себе и данные (поля класса), и методы для работы с этими данными. 3. Всё получится!
Vladimir “Rain_Senpai1995” Soldatenko Уровень 35, Киев, Украина
14 сентября 2020
Глупый вопрос: можно ли, что бы сеттер возвращал обьект. Например:

public Book setName (String name){
this.name = name;
return this;
}
Ведь, таким образом, можно сделать цепочку вызовов сеттеров и сократить количество кода! Можно ли?
DZ Уровень 35, Россия
9 июля 2020
Да не пользуюсь я Гуглом, я всегда пользовался только Яндексом. Почему есть глагол "гуглить" и нет "яндексить"? По-моему именно из-за такого шаблона доля Гугла растет каждый год