Найти в Дзене
"Мы"-Прогер

Изучаем C# - Инкапсуляция в ООП

Объектно-ориентированное программирование (ООП) - это такой подход к программированию, в котором программа представляет собой совокупность взаимодействующих между собой объектов. Мы уже знаем, что класс - это свой тип данных, описывающий, как устроен каждый объект; объекты - это конкретные экземпляры класса. Однако ООП подразумевает нечто большее, чем просто то, что каждая переменная является объектом. Существует 4 основных принципа ООП: Они сложные, но очень мощные. Их надо знать обязательно. Тем более, что эти принципы общие для всех Си-подобных языков. Сейчас мы разберём первый из них. Пусть мы хотим сделать забег животных. У каждого животного будет кличка, чтобы можно было их различать. Животные бегут по прямой, то есть, у каждого из них есть одна координата - X. У каждого животного есть скорость Speed - за одну условную единицу времени координата X увеличивается на Speed. Все животные бегут только в одном направлении, то есть, X не может уменьшаться. Скорость каждого животного обо
Оглавление

Что такое объектно-ориентированное программирование?

Объектно-ориентированное программирование (ООП) - это такой подход к программированию, в котором программа представляет собой совокупность взаимодействующих между собой объектов. Мы уже знаем, что класс - это свой тип данных, описывающий, как устроен каждый объект; объекты - это конкретные экземпляры класса. Однако ООП подразумевает нечто большее, чем просто то, что каждая переменная является объектом. Существует 4 основных принципа ООП:

  1. Инкапсуляция
  2. Наследование
  3. Полиморфизм
  4. Абстракция

Они сложные, но очень мощные. Их надо знать обязательно. Тем более, что эти принципы общие для всех Си-подобных языков.

Сейчас мы разберём первый из них.

Модификатор readonly

Пусть мы хотим сделать забег животных. У каждого животного будет кличка, чтобы можно было их различать. Животные бегут по прямой, то есть, у каждого из них есть одна координата - X. У каждого животного есть скорость Speed - за одну условную единицу времени координата X увеличивается на Speed. Все животные бегут только в одном направлении, то есть, X не может уменьшаться. Скорость каждого животного обозначается при его создании и не может изменяться.

Сделаем класс Animal ("Животное"). У каждого животного будет кличка Name, а значит, в классе будет поле Name:

Разумеется, кличка не должна меняться после создания животного. Но сейчас кто-нибудь может нечаянно её изменить:

-2

Чтобы исправить это, добавим к полю Name модификатор readonly ("только чтение"):

-3

Поля, помеченные readonly, могут устанавливаться только при создании объекта и потом уже не могут меняться. Попытка изменить такое поле приведёт к ошибке:

-4

Уберём попытку изменить имя:

-5

Всё станет хорошо. Зачем это нужно, мы разберём чуть ниже.

Аналогичным образом добавьте скорость и сделайте, чтобы её нельзя было менять после создания животного.

Что такое инкапсуляция?

У животного будут X и Speed, а значит, в классе Animal будут такие поля. Какие действия можно делать над животным? Сдвинуть его за единицу времени на Speed. Значит, в классе будет метод Move():

-6

Но сейчас кто-нибудь может сломать работу класса, напрямую задав координату X:

-7

Здесь readonly уже не поможет, потому что X должна меняться при вызове Move().

Чтобы никто нечаянно не мог влезть в логику работы класса, поля и методы класса можно защищать. Есть такие модификаторы доступа, которые можно навешивать на поля и методы:

  1. public - доступно везде
  2. protected - недоступно снаружи класса, но доступно в классах-наследниках (разберём это в теме "Наследование")
  3. private - недоступно снаружи и в классах-наследниках. Доступно только изнутри класса.

Каждый следующий модификатор доступа более строг, чем предыдущий. Это основные модификаторы доступа, они есть во всех си-подобных языках. Кроме них конкретно в C# есть ещё другие, но они почти не используются. См. https://yandex.ru/search/?text=c%23+модификаторы+доступа

Заменим в определении поля X public на private. Теперь поле X не видно снаружи класса:

-8

Так что никто не может нечаянно испортить X. Вот это, когда мы делаем поля и методы невидимыми снаружи, как бы заключаем их в капсулу, и называется инкапсуляцией. Инкапсуляция защищает логику класса от вмешательств извне. Класс превращается в "чёрный ящик", которым другие программисты могут пользоваться, не зная, как он устроен внутри и изучив только public-поля и методы. То есть, для пользования классом больше не нужно изучать код внутри него, что упрощает командную работу.

Но теперь мы не можем узнать координату животного, так как X не виден снаружи. Поэтому нам придётся сделать метод, который будет выдавать наружу значение X:

-9

Итак, чтобы воспользоваться нашим классом, другим программистам больше не нужно знать, по каким правилам меняется X - им достаточно знать публичные поля и методы: что конструктор принимает на вход кличку и скорость, что есть метод Move(), который нужно вызывать по прошествии единицы времени, и что есть метод GetX(), который позволяет узнать координату. Всё упростилось - чтобы устроить забег, больше не нужно знать, как работают X, Speed и подобное!

-10

Найдите животное, которое выиграло забег, и распечатайте сообщение в формате "Победитель: {Имя}".

Предупреждения и улучшения Rider

Вернёмся в класс. Там горит несколько улучшений.

-11

"Поле 'Speed' может быть сделано приватным". Подумаем - правда ли стоит сделать его приватным? Оно не используется нигде снаружи и не будет использоваться, по крайней мере, для записи. Всегда, когда можно, надо использовать более строгий модификатор доступа. Можно либо вручную заменить public на private, либо поставить туда каретку для ввода текста и нажать на лампочку:

-12

Теперь название поля Speed подсветится жёлтым:

-13

"Имя 'Speed' не соответствует правилу 'Поля экземпляров (private)'. Предлагаемое имя - '_speed'". По стилю кода, приватные поля принято называть, начиная с подчёркивания и с маленькой буквы. Публичные поля - с большой (без подчёркивания). Исправляем таким же образом:

-14

Исправьте также и X.

А вот применять "Преобразовать в первичный конструктор" здесь нет особого смысла - из кода получится каша. Попробуйте и верните назад через Ctrl + Z.

-15

Далее

Свойства, геттеры и сеттеры - https://dzen.ru/a/aaAKjosrTz0TTFNA?share_to=link

Оглавление - https://dzen.ru/a/aXisxwt_Mnz2qTjs?share_to=link