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

214
17 июня 2022, 16:40

Начал изучать объектно-ориентированное программирование. Со всеми принципами разобрался, но не могу до конца осмыслить, для чего нужна инкапсуляция. В моем понимании это контроль входящих данных и более ничего, но разве нет ничего более существенного?

Answer 1

Более того - инкапсуляция: это самый важный принцип не только ООП, а программирования в принципе. Наследование, и полиморфизм - это строго говоря не принципы вовсе, скорее некоторые свойства ООП-систем связанные с переиспользованием кода.

Почему же так важна инкапсуляция: представьте себе код не учебной задачки, а код огромного проекта, где только кода (со всякими библиотеками) на гигабайт. А теперь представьте, что в этом коде всё крепко-накрепко друг с другом перевязано. Как думаете, возможно будет такой код анализировать в принципе? Даже если предположить что возможно: то очевидно изменение каждого метода будет провоцировать понижение стабильности. ООП старается проецировать реальный мир на код: в реальном мире вода, налитая в чашку не будет проникать в керамику, кнопка от клавиатуры не будет участвовать в вычислениях, а человеческий мозг не будет помогать сердцу толкать кровь. А принцип инкапсуляции - это и есть принцип устранения связей, то есть то, что позволяет объектам не "перемешиваться".

Именно обособление, которое даёт инкапсуляция - позволяет уложить даже огромные объёмы кода в голову, разделяй и властвуй - это ещё древняя поговорка для реального мира отлично работает и для мира цифрового. А также дополнительно защищает вас от ошибок: компьютер не перестанет работать, если случайно сломать кнопку от клавиатуры(инкапсулированный код). Простота кода объекта X как-раз измеряется количеством открытых связей между объектом X и другими объектами - то есть если этих связей очень много: то очень проблематично положить объект X к себе в голову, проблематично даже дать объективное название объекту X- так как он даёт о себе слишком много разнородной информации.

Инкапсуляция проявляется не только в private и protected. Метод класса инкапсулирует в себе алгоритм и переменные. Вы можете не бояться делать неразборчивые четырёхъярусные алгоритмы внутри метода класса, так как программист которому понадобится класс будет смотреть не на содержимое метода, а на название метода. Это тоже инкапсуляция, работает принцип сокрытия - программисту неважно что внутри, при этом он понимает как всё работает. Тоже самое относится к функциям-замыканиям: они для того и созданы, чтобы обособлять внутри себя алгоритм с переменными для его работы. То есть функции тоже работают прежде всего на инкапсуляцию - т.к. переменные внутри функции, алгоритм их использующий, может совершенно не беспокоить того кто использует функцию. И я бы даже сказал, что функции в современном программировании инкапсулируют гораздо больше, чем модификаторы видимости в классах - яркие примеры сплошь и рядом на JavaScript.

Подытожу свой ответ - инкапсуляция это почти что то же самое, что и обособление. Именно обособление - ключевая вещь, которая помогает систему любых размеров уложить в голове. Инкапсуляция уменьшает количество связей между объектами - думать о них, и прокручивать в голове механизм их работы становится гораздо проще, разработка ускоряется.
Разделяй и властвуй. Однако это верно только для средних-больших проектов, с множеством подключаемых библиотек. На небольшой задаче реальную пользу инкапсуляции увидеть можно только когда пренебрегая использованием функций/классов, у вас образуется слишком большой стек глобальных переменных, от которых голова пойдёт кругом.

Answer 2

Инкапсуляция - сокрытие данных. Приведу простой пример. Допустим у нас есть прямоугольник, у которого поля открыты (модификатор доступа public):

public class Rectangle {
    public int width;
    public int height;
}

Вы же можете написать следующий код:

Rectangle rect = new Rectangle();
rect.width = -1;
rect.height = -1;

С точки зрения компилятора все отлично, -1 имеет тип int, ничего незаконного мы не делаем. Но Вы то понимаете, что так делать нельзя (что означает отрицательная высота?) и хочется как-то избавиться от этой ошибки. Что можно сделать? А можно сделать следующее:

public class Rectangle {
    private int width;
    private int height;
    public void setHeight(int value) {
        if(value <= 0) throw new IllegalArgumentException();
        height = value;
    }
    public int getHeight() {
        return height;
    }
    //Тоже самое с width
}

Что изменилось? У поля height модификатор доступа стал private, то есть теперь за границамы класса мы не можем получить к нему доступ. Но ведь это тоже не дело, мы, скорее всего, захотим использовать это поле у себя в коде. Для этого был добавлен метод (называется геттер) getHeight(). Также, добавился метод (называется сеттер), который, собственно, и решает нашу проблему (с отрицательными значениями). Теперь, если попытаться сделать следующее:

Rectangle rect = new Rectangle();
rect.setHeight(-1) ; //IllegalArgumentException!

Будет ошибка!

Таким образом, мы "скрыли" поля (используя модификатор private) и задаем их значение через методы (называемые сеттерами), в которых можем проверять данные на корректность (валидация). Теперь другие программисты (если Вы работаете в команде) или Вы сами не смогут "поламать" Ваш обьект (сделать так чтобы что-то перестало работать). Разумеется, пример приведенный мною, является очень простым. На практике (когда Вы работаете в команде) все не так очевидно. В конце концов, Вы можете просто ошибиться и, допустим, поделить на 0 (это Java сообщит Вам об ошибке, а на C++ программа аварийно завершиться и потом гадай в какой строке из миллиона что-то не так!!!).

Answer 3

Инкапсуляция (encapsulation) - это механизм, который объединяет данные и код, манипулирующий этими данными, а также защищает и то, и другое от внешнего вмешательства или неправильного использования.

(from codenet.ru)

Инкапсуляция нужна для того, что бы пользователь не мог использовать не предназначенный для него функционал. Почитайте Гради Буча "Объектно-ориентированный анализ и проектирование с примерами приложений на С++". У него нормально расписано и примеры интересные.

Система должна быть закрыта, как Ганнибал Лектор в камере. Мы знаем как узнать жив ли он еще и как дать ему покушать. Больше взаимодействовать с ним нельзя. Могут быть последствия.

Очередной апдейт. Компьютерную программу можно рассматривать как систему, состоящую из функционала предназначенного для пользователя и функционала предназначеного для служебного использования. Служебный функционал следует скрывать, что бы не вводить пользователя в недоумение и не дать ему возможности изменить внутреннее состояние системы не подобающим образом.

Answer 4

Объект "знает" свое состояние, и когда его "попросите", чтобы свое состояние изменил, сделает то так, чтобы его состояние было всегда консистентным.

Пример:

  • Объект: Время в виде минуты:секунды вместе с методом увеличения на любые количество секунд.
  • Состояние: 7:42.
  • Просьба: Увеличивай свое состояние на 20 секунд.
  • Новое состояние: 8:02.

Когда бы вы сохраняли минуты и секунды в 2 независимых переменных, тогда на всяком месте программы, где бы вы добавили секунды, должны были опять и опять проверять, если не нужно изменить тоже количество минут - и могли бы это забыть.

И каждому, кто бы хотел добавить что-то до вашей программы, указать на это.

Answer 5

Как указано в википедии с трактовкой термина не все просто. Под ним могут подразумевать механизм ограничения доступа и/или конструкцию языка позволяющую упаковывать данные и методы обработки этих данных. Если по ограничению доступа вам много написали и это достаточно просто для понимания, то с упаковкой у начинающих все плохо и с чистой совестью для каждого поля класса создаются пара get set методов. В подавляющем большинстве случаев это явный признак того, что имеет место нарушение инкапсуляции. Объект должен сам обрабатывать свои данные, а не быть просто контейнером для них. Объект это данные + поведение, в противном случае это не объект в том смысле, который вкладывал в него автор ООП. И на мой взгляд это является более важным, чем просто механизм ограничения доступа.

READ ALSO
При перемещении exe+dll вылетает ошибка C#

При перемещении exe+dll вылетает ошибка C#

При запуске программы на моём пк всё нормально, но если запускать на другом, то выводит следующую ошибку

181
&quot;Assembly will not load due to errors&quot; Unity

"Assembly will not load due to errors" Unity

Делаю приложение на Unity, в котором нужно использовать базу данных, которая хранится на хостингеПри попытке добавить библиотеку MySql

232
Выборка данных из Mysql по id

Выборка данных из Mysql по id

Какой запрос Mysql нужно написать чтобы извлечь данные по id которые выделены на скриншоте

276
Unity. Проблема с заполнением массива

Unity. Проблема с заполнением массива

Написал код, который должен заполнять стринговый массив с клавиатуры через поле ввода

181