1. Вступ
Хочемо присвятити сьогоднішню лекцію інкапсуляції. Ви вже знаєте в загальних рисах, що це таке.
У чому ж переваги інкапсуляції? Їх досить багато, але я можу виділити чотири, на мою думку, основних:
2. Валідний внутрішній стан
У програмах часто виникають ситуації, коли кілька класів взаємодіють з одним і тим же об'єктом. У результаті їхньої спільної роботи порушується цілісність даних усередині об'єкта — він уже не може продовжувати нормально працювати.
Тому об'єкт повинен стежити за змінами своїх внутрішніх даних, а ще краще — здійснювати їх самостійно.
Якщо ми не хочемо, щоб якась змінна класу змінювалася іншими класами, ми оголошуємо її private, і тоді тільки методи цього ж класу зможуть отримати до неї доступ. Якщо ми хочемо, щоб значення змінних можна було тільки читати, але не змінювати, тоді потрібно додати public getter для потрібних змінних.
Наприклад, ми хочемо, щоб усі могли дізнатися кількість елементів у нашій колекції, але ніхто не міг його змінити без нашого дозволу. Тоді ми оголошуємо змінну private int count і метод public getCount().
Правильне використання інкапсуляції гарантує, що жоден клас не може отримати прямий доступ до внутрішніх даних нашого класу і, як наслідок, змінити їх без контролю з нашого боку. Тільки через виклик методів того ж класу, що й змінювані змінні.
Краще виходити з того, що інші програмісти завжди будуть використовувати ваші класи найзручнішим для них способом, а не найбезпечнішим для вас (для вашого класу). Звідси й помилки, і спроби заздалегідь усунути їх.
3. Контроль переданих аргументів
Іноді треба контролювати аргументи, передані в методи нашого класу. Наприклад, наш клас описує об'єкт "людина" і дозволяє задати дату її народження. Ми повинні перевіряти всі передані дані на їхню відповідність логіці програми та логіці нашого класу. Наприклад, не допускати 13-й місяць, дату народження 30 лютого і так далі.
Навіщо ж комусь вказувати в даті народження 30 лютого? По-перше, це може бути помилка введення даних від користувача. По-друге, перш ніж програма буде працювати як годинник, у ній буде багато помилок. Наприклад, можлива така ситуація.
Програміст пише програму, яка визначає людей, у яких день народження післязавтра. Наприклад, сьогодні 3 березня. Програма додає до поточного дня місяця число 2 і шукає всіх, хто народився 5 березня. Ніби все вірно.
От тільки коли настане 30 березня, програма не знайде нікого, тому що в календарі немає 32 березня. У програмі стає значно менше помилок, коли в методи додають перевірку переданих даних.
Пам'ятаєте, коли ми вивчали ArrayList і розбирали його код, і там була перевірка індексу в методах get і set: index більше або дорівнює нулю і менше довжини масиву. Там ще викидалося виключення, якщо в масиві немає елемента з таким індексом. Це класичний приклад перевірки вхідних даних.
4. Мінімізація помилок при зміні коду класів
Уявімо, що ми написали один дуже корисний клас, коли брали участь у великому проєкті. Він так усім сподобався, що інші програмісти почали використовувати його в сотнях місць у своєму коді.
Клас виявився настільки корисним, що ви вирішили його покращити. Але якщо ви видалите якісь методи цього класу, код десятків людей перестане компілюватися. Їм доведеться терміново все переробляти. І чим більше переробок, тим більше помилок. Ви поламаєте купу збірок, і вас будуть ненавидіти.
А коли ми змінюємо методи, оголошені як private, ми знаємо, що ніде немає жодного класу, який викликав би ці методи. Ми можемо їх переробити, змінити кількість параметрів і їхні типи, і залежний код працюватиме далі. Ну або принаймні компілюватися.
5. Задаємо спосіб взаємодії нашого об’єкта з іншими об’єктами
Ми можемо обмежити деякі дії, допустимі з нашим об'єктом. Наприклад, ми хочемо, щоб об'єкт можна було створити тільки в одному екземплярі. Навіть якщо його створення відбувається в кількох місцях проєкту одночасно. І ми можемо зробити це завдяки інкапсуляції.
Інкапсуляція дозволяє додавати додаткові обмеження, які можна перетворити на додаткові переваги. Наприклад, клас String реалізовано як immutable (незмінний) об'єкт. Об'єкт класу String незмінний з моменту створення і до моменту "смерті". Усі методи класу String (remove, substring, ...), повертають новий рядок, абсолютно не змінюючи об'єкт, у якого вони були викликані.
Інкапсуляція дуже цікава штука.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ