Инкапсуляция || C#
Сегодня поговорим об одной из известных фишек ООП.
Что такое инкапсуляция и зачем она нужна?
Инкапсуляция - это правило, при котором присваивание и изменение данных ограничено, что защищает их от случайных или неосознанных изменений. Её легко использовать в коде и она не занимает много строчек кода.
Проблема, которую мы сегодня разберём


Класс MyClass и его использование
У нас есть класс MyClass с полем Value типа int. С этим полем мы можем сделать всё, что захотим: присваивать как угодно, когда угодно и менять на что угодно.
Давайте представим, что этот класс может хранит только отрицательное значение Value.
Я вам сегодня покажу два решения данной проблемы и ещё один кейс с более продвинутым решением.
Способ 1: Через свойства
Данный подход делает код более красивым, но имеет свои оговорочки, потом расскажу.
Какие изменения я внёс:
Теперь Value не поле, а свойство, возвращающее приватное поле value. Здесь инкапсуляцией выступает сеттер (set {...}):
В сеттере мы обрабатываем поступающее значение: если оно меньше нуля, то мы приватному полю value оно присваивается, а иначе вызывается ошибка.
Использовать свойства на самом деле хороший минималистичный способ инкапсуляции, но его главный минус -- это отсутствие параметров: можно только присвоить новое значение, а задать другие параметры, например множитель, нельзя.
Способ 2: Через методы
Данный подход является самым часто-используемым и универсальным в ООП.


Изменённый класс MyClass
Какие изменения я внёс:
Я удалил свойство Value, заменив его методом. Теперь я могу добавить любой параметр в метод, например, множитель, но в данном кейсе это не нуждается. Использование класса я тоже изменил.
Теперь разберём второй кейс:
Допустим у нас есть тот же класс MyClass и у него есть экземпляр класса MyClassData. Этот класс хранит в себе переменные Name (имя) и Age (возраст).
Но у нас есть проблема: мы можем изменять всё, что захотим и когда захотим. Тогда нам на помощь приходит инкапсуляция:
Какие изменения я внёс:
Сначала я сделал MyClassData структурой, ведь он просто хранит данные, а не проводит над ними операции. В класса MyClass я сделал экземпляр приватным, а его данные передаются через свойства только для чтения. На самом деле можно и сразу структуру передавать, или если данных слишком много, а передавать надо только некоторые, можно создать новую структуру, заполнять нужными данными и так передавать.
Инкапсуляция при работе с массивами и листами
Массивы и листы являются ссылочными типами, сейчас я вам докажу:


Класс с массивом и его использование
Новый кейс: у нас есть класс MyClass с массивом myArray, защищённым от присваивания, но вот в чём проблема: мы как бы не можем присвоить, но мы можем изменить, ведь это ссылочный тип. А если дело доходит до листов (List<T>), то вообще можно всё менять методами.
Сейчас я вам покажу, как исправить такую ситуацию:
Теперь наше свойство превращается в приватное поле, а получать доступ дял чтения мы будем через метод GetElement(int index), где index обозначает... ну вы поняли.
А давайте теперь добавим возможность "инвертировать значения":
Я добавил метод Reverse, который по индексу будет переворачивать нужное значение. На этом примере хорошо прослеживается инкапсуляция.
Что когда использовать?
Используй свойства там, где нуждается простое присваивание переменной value-типа, присваивание некоторых полей экземпляров ссылочного типа. Просто присвоить что-то.
Используй методы там, где определённую переменную можно изменять разными способами (например, изменение на 1 и вычитание на 2). Также методы можно использовать, чтобы изменять переменную с помощью нескольких аргументов, особенно при работе с массивами и листами.





