Обидві нинішні відповіді, здається, лише частково досягли позначки, і вони зосереджуються на прикладах, які затьмарюють основну думку. Це також не (виключно) принцип ООП, а загалом принцип розробки програмного забезпечення.
Річ, яка "варіюється" у цій фразі, - це код. Крістоф наголошує на тому, що зазвичай щось може відрізнятися, тобто ви часто цього передбачаєте . Мета - захистити себе від майбутніх змін у коді. Це тісно пов'язане з програмуванням на інтерфейс . Однак Крістоф невірно обмежувати це "деталями реалізації". Насправді цінність цієї поради часто пояснюється змінами вимог .
Це лише опосередковано пов'язане з інкапсулюючим станом, про що я думаю, Девід Арно думає. Ця порада не завжди (але часто є) передбачає стан інкапсуляції, і ця порада стосується також незмінних об'єктів. Насправді просто називання констант є (дуже базовою) формою інкапсуляції того, що змінюється.
CandiedOrange прямо пов'язує "те, що змінюється", з "деталями". Це лише частково правильно. Я погоджуюся, що будь-який код, який змінюється, є "деталями" в якомусь сенсі, але "деталь" може не змінюватися (якщо ви не визначите "деталі", щоб зробити це тавтологічним). Можуть бути причини для інкапсуляції неоднакових деталей, але цей диктум не один. Грубо кажучи, якщо ви були впевнені, що "собака", "кішка" і "качка" будуть єдиними типами, з якими вам коли-небудь доведеться мати справу, то цей диктум не пропонує реконструювати CandiedOrange.
Прикладаючи приклад CandiedOrange в іншому контексті, припустимо, що у нас є процедурна мова типу C. Якщо у мене є код, який містить:
if (pet.type() == dog) {
pet.bark();
} else if (pet.type() == cat) {
pet.meow();
} else if (pet.type() == duck) {
pet.quack()
}
Я можу з розумом очікувати, що цей фрагмент коду зміниться в майбутньому. Я можу "інкапсулювати" це, просто визначивши нову процедуру:
void speak(pet) {
if (pet.type() == dog) {
pet.bark();
} else if (pet.type() == cat) {
pet.meow();
} else if (pet.type() == duck) {
pet.quack()
}
}
і використання цієї нової процедури замість блоку коду (тобто рефакторинг "методом вилучення"). У цей момент додавання типу "корова" або все, що вимагає лише оновлення speak
процедури. Звичайно, мовою ОО ви можете замість цього використовувати динамічну розсилку, на яку згадується у відповіді CandiedOrange. Це станеться природно, якщо ви отримаєте доступ pet
через інтерфейс. Усунення умовної логіки за допомогою динамічної диспетчеризації є ортогональним питанням, яке було частиною того, чому я зробив це процедурне передання. Я також хочу наголосити, що для OOP для цього не потрібні особливості. Навіть мовою ОО, інкапсуляція різниць не означає, що потрібно створити новий клас або інтерфейс.
Як більш архетипний приклад (який ближчий, але не зовсім ОО), скажімо, що ми хочемо видалити дублікати зі списку. Скажімо, ми реалізуємо це шляхом ітерації над списком, відслідковуючи елементи, які ми бачили до цього часу, в іншому списку та видаляючи будь-які елементи, які ми бачили. Доцільно припустити, що ми, можливо, захочемо змінити те, як ми слідкуємо за побаченими предметами, принаймні, з причин виконання. Дані щодо інкапсуляції того, що змінюється, підказує, що ми повинні побудувати абстрактний тип даних для представлення набору бачених елементів. Тепер наш алгоритм визначений у порівнянні з цим абстрактним типом даних набору даних, і якщо ми вирішимо перейти на двійкове дерево пошуку, наш алгоритм не потребує змін або догляду. Мовою ОО, ми можемо використовувати клас або інтерфейс для зйомки цього абстрактного типу даних. Мовою на зразок SML / O '
Для прикладу, орієнтованого на вимоги, скажіть, що вам потрібно перевірити деяке поле стосовно певної логіки бізнесу. Хоча зараз у вас можуть бути конкретні вимоги, ви сильно підозрюєте, що вони розвиватимуться. Ви можете інкапсулювати поточну логіку у власній процедурі / функції / правилі / класі.
Хоча це ортогональне занепокоєння, яке не є частиною "інкапсуляції того, що змінюється", часто природним є абстрагування, тобто параметризація за теперішньою капсульованою логікою. Це, як правило, призводить до більш гнучкого коду і дозволяє змінювати логіку заміною в альтернативній реалізації, а не змінюючи інкапсульовану логіку.