Термін «інкапсуляція», він же перший принцип ООП, має два трактування. Найчастіше фахівці використовують цей термін тільки в одному значенні, забуваючи про інше, а це невірно.
Перша трактування – в один об’єкт або клас об’єднуються і дані, і методи, які працюють з цими даними. Друге трактування – інкапсуляція це приховування внутрішньої структури об’єкта від зовнішніх впливів. Всі зміни стану об’єкта відбуваються тільки за допомогою звернень до методів самого об’єкту.
Особисто я розумію під терміном «інкапсуляція» обидві ці трактування – і з’єднання методів з даними, і приховування даних від зовнішніх впливів, зміна їх тільки через звернення до методів самого об’єкту. Справа в тому, що друга трактування без першої не працює зовсім. Що ви будете приховувати, якщо у вас в об’єкті не буде методів і даних?
До чого відноситься принцип інкапсуляції? З точки зору ООП, об’єктом є не тільки клас або об’єкт, або як це називається в вашій мові програмування, а й інші структури, більш високого рівня, а саме: packages, namespaces, модулі, сабмодулі, підсистеми і вся система цілком. Якщо розглядати инкапсуляцию як приховування, ми розуміємо, що наш об’єкт не повинен змінюватися нічим зовні, крім його ж методів. Це допоможе уникнути випадкових взаємодій типу «гайку відкрутили – жопа відвалилася».
Якщо до стану об’єкта має доступ тільки сам об’єкт – я нагадую, що стан об’єкта це значення всіх його полів – то це нам дозволяє уникнути зайвих взаємозв’язків, несподіваних сайд ефектів, коли об’єкт працював-працював, і тут у нього раптово змінилося поле, і в ньому вже зовсім інше значення. Програма вилітає, і виходять інші проблеми типу raise condition.
Для програміста важливо пам’ятати, що завжди має сенс приховувати всі дані, закривати всі стану об’єкта від зовнішнього об’єкта, і пам’ятати про те, що приховування внутрішньої структури вашого модуля від зовнішнього втручання, теж має сенс. Звернення через інтерфейс або через його зовнішній паблік клас – це робота з модулем через його фасад, через сервіс, а не грубі роботи з чорного ходу, щоб подивитися, що там всередині.
Робота між модулями повинна йти тільки через прийняті інтерфейси, а не безпосередньо викликом якихось методів, які наступна команда може поміняти, і вони будуть працювати не так. Навіть якщо інтерфейс залишиться тим же, метод може діяти інакше. Через порушення інкапсуляції ми отримуємо велику кількість порушень, дисфункцію системи, складну підтримку – коли не можна, наприклад, швидко виправити баг або внести новий функціонал.
З принципу інкапсуляції безпосередньо виникає безліч паттернів GRASP. Наприклад, патерн GRASP “Information expert” – це пряма імплементація паттерна інкапсуляції. Де повинні оброблятися дані? В об’єкті, який їх містить. Це приватна, більш специфічна формулювання тієї ж самої інкапсуляції.
Те ж саме стосується low coping. Менше зв’язків між об’єктами означає, що до об’єктів ми звертається тільки через потрібні методи, а не смикаємо все підряд, не використовуємо reflection, щоб длубатися в кишках об’єкта. Тільки через паблік інтерфейс, тільки через методи, спочатку призначені для того, щоб до них звертатися.
Знання декількох принципів звільняє від знання багатьох фактів. Програмісти, які пам’ятають, що таке інкапсуляція в широкому сенсі – не лазити, куди не слід, чи не проскакувати між Лейер, не лізти в базу поверх UI – менше стикається з сайд ефектами. Будь-яке порушення структури програми загрожує ефектами, і всі їх можна звести до порушення інкапсуляції.