HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-21
1 <p><a>#Руководства</a></p>
1 <p><a>#Руководства</a></p>
2 <ul><li>9 окт 2019</li>
2 <ul><li>9 окт 2019</li>
3 <li>0</li>
3 <li>0</li>
4 </ul><p>Классы, методы и поля не всегда могут постоять за себя. Рассказываем, как быть защитником в объектно-ориентированном программировании.</p>
4 </ul><p>Классы, методы и поля не всегда могут постоять за себя. Рассказываем, как быть защитником в объектно-ориентированном программировании.</p>
5 <p>vlada_maestro / shutterstock</p>
5 <p>vlada_maestro / shutterstock</p>
6 <p>Пишет о программировании, в свободное время создаёт игры. Мечтает открыть свою студию и выпускать ламповые RPG.</p>
6 <p>Пишет о программировании, в свободное время создаёт игры. Мечтает открыть свою студию и выпускать ламповые RPG.</p>
7 <p>Инкапсуляция в программировании может показаться довольно сложной темой. Тем не менее, её необходимо освоить для уверенной работы с парадигмой ООП. В этой статье мы познакомимся с концепцией инкапсуляции и рассмотрим её на примере уровней доступа.</p>
7 <p>Инкапсуляция в программировании может показаться довольно сложной темой. Тем не менее, её необходимо освоить для уверенной работы с парадигмой ООП. В этой статье мы познакомимся с концепцией инкапсуляции и рассмотрим её на примере уровней доступа.</p>
8 <ul><li><a>Что такое классы и объекты</a>.</li>
8 <ul><li><a>Что такое классы и объекты</a>.</li>
9 <li><a>Особенности работы с объектами</a>.</li>
9 <li><a>Особенности работы с объектами</a>.</li>
10 <li><a>Модификаторы доступа, инкапсуляция</a>.</li>
10 <li><a>Модификаторы доступа, инкапсуляция</a>.</li>
11 <li><a>Полиморфизм и перегрузка методов</a>.</li>
11 <li><a>Полиморфизм и перегрузка методов</a>.</li>
12 <li><a>Полиморфизм</a>.</li>
12 <li><a>Полиморфизм</a>.</li>
13 <li><a>Наследование и ещё немного полиморфизма</a>.</li>
13 <li><a>Наследование и ещё немного полиморфизма</a>.</li>
14 <li><a>Абстрактные классы и интерфейсы</a>.</li>
14 <li><a>Абстрактные классы и интерфейсы</a>.</li>
15 <li><a>Практикум</a>.</li>
15 <li><a>Практикум</a>.</li>
16 </ul><p>Представьте автомобиль с автоматической коробкой передач (АКП). Во время езды водитель такой машины выполняет три действия: крутит руль на поворотах; нажимает педаль газа, чтобы ускориться, и педаль тормоза - чтобы остановиться. Он не задумывается, о том, как работает сцепление, и не может "перескочить" со второй ступени на четвертую. В его распоряжении есть лишь ограниченный набор органов управления, с помощью которых он воздействует на автомобиль.</p>
16 </ul><p>Представьте автомобиль с автоматической коробкой передач (АКП). Во время езды водитель такой машины выполняет три действия: крутит руль на поворотах; нажимает педаль газа, чтобы ускориться, и педаль тормоза - чтобы остановиться. Он не задумывается, о том, как работает сцепление, и не может "перескочить" со второй ступени на четвертую. В его распоряжении есть лишь ограниченный набор органов управления, с помощью которых он воздействует на автомобиль.</p>
17 <p>А вот у водителя, скажем, ВАЗ 2105 с механической коробкой передач больше свободы действий, но с ней приходит и большая ответственность. Если игнорировать внутреннее устройство автомобиля, то можно "подпалить сцепление" или вывести из строя выжимной подшипник.</p>
17 <p>А вот у водителя, скажем, ВАЗ 2105 с механической коробкой передач больше свободы действий, но с ней приходит и большая ответственность. Если игнорировать внутреннее устройство автомобиля, то можно "подпалить сцепление" или вывести из строя выжимной подшипник.</p>
18 <p>Хотя некоторые водители предпочитают "механику", среднестатистическому городскому жителю, куда удобнее и безопаснее ездить на "автомате". Ведь с АКП даже начинающий водитель, скорее всего, не нанесет вред автомобилю неумелыми действиями.</p>
18 <p>Хотя некоторые водители предпочитают "механику", среднестатистическому городскому жителю, куда удобнее и безопаснее ездить на "автомате". Ведь с АКП даже начинающий водитель, скорее всего, не нанесет вред автомобилю неумелыми действиями.</p>
19 <p>Описанный выше принцип и называется инкапсуляцией. Процессы, происходящие под капотом автомобиля, скрыты от водителя, а управление осуществляется через удобный и безопасный "интерфейс" - руль и педали. Такой же принцип лежит в основе ООП.</p>
19 <p>Описанный выше принцип и называется инкапсуляцией. Процессы, происходящие под капотом автомобиля, скрыты от водителя, а управление осуществляется через удобный и безопасный "интерфейс" - руль и педали. Такой же принцип лежит в основе ООП.</p>
20 <p><strong>Инкапсуляция</strong><em>(от лат. in capsule - в оболочке)</em>- это заключение данных и функциональности в оболочку. В объектно-ориентированном программировании в роли оболочки выступают классы: они не только собирают переменные и методы в одном месте, но и защищают их от вмешательства извне<em>(сокрытие)</em>.</p>
20 <p><strong>Инкапсуляция</strong><em>(от лат. in capsule - в оболочке)</em>- это заключение данных и функциональности в оболочку. В объектно-ориентированном программировании в роли оболочки выступают классы: они не только собирают переменные и методы в одном месте, но и защищают их от вмешательства извне<em>(сокрытие)</em>.</p>
21 <p>Методы позволяют контролировать обращение к данными и предотвратить их удаление или некорректное изменение. Например, можно запретить присваивать полю "возраст" объекта "Пользователь" число большее 130. Другими словами, это такая "защита от дурака" в программировании.</p>
21 <p>Методы позволяют контролировать обращение к данными и предотвратить их удаление или некорректное изменение. Например, можно запретить присваивать полю "возраст" объекта "Пользователь" число большее 130. Другими словами, это такая "защита от дурака" в программировании.</p>
22 <p>Первый уровень, с которым сталкиваются все разработчики, - публичный. Чтобы сказать компилятору, что что-то должно быть доступно для всех, используется ключевое слово<strong>public</strong>.</p>
22 <p>Первый уровень, с которым сталкиваются все разработчики, - публичный. Чтобы сказать компилятору, что что-то должно быть доступно для всех, используется ключевое слово<strong>public</strong>.</p>
23 <p>Рассмотрим на примере класса<em>Item</em>:</p>
23 <p>Рассмотрим на примере класса<em>Item</em>:</p>
24 public class Item { public string name; public int cost; public Item(string name, int cost) { this.name = name; this.cost = cost; } }<p>Объявив экземпляр этого класса, можно обращаться к любым его полям в любом месте программы, где доступен сам объект (речь о локальных и глобальных переменных).</p>
24 public class Item { public string name; public int cost; public Item(string name, int cost) { this.name = name; this.cost = cost; } }<p>Объявив экземпляр этого класса, можно обращаться к любым его полям в любом месте программы, где доступен сам объект (речь о локальных и глобальных переменных).</p>
25 Item sword = new Item("Sword of Destiny", 500000); Console.WriteLine($"You've got {sword.name}! It costs {sword.cost} rubles.");<p>Так как поля публичные, в консоли они отобразятся без каких-либо проблем:</p>
25 Item sword = new Item("Sword of Destiny", 500000); Console.WriteLine($"You've got {sword.name}! It costs {sword.cost} rubles.");<p>Так как поля публичные, в консоли они отобразятся без каких-либо проблем:</p>
26 <p>Это удобно, потому что можно в любой момент выполнить любое действие над объектом и его данными. Но в этом и кроется проблема: объект становится беззащитен перед любым вмешательством. Например, можно просто взять и изменить его цену:</p>
26 <p>Это удобно, потому что можно в любой момент выполнить любое действие над объектом и его данными. Но в этом и кроется проблема: объект становится беззащитен перед любым вмешательством. Например, можно просто взять и изменить его цену:</p>
27 sword.cost = 50; Console.WriteLine($"You've got {sword.name}! It costs {sword.cost} rubles.");<p>Из-за того, что поле публичное, оно изменится:</p>
27 sword.cost = 50; Console.WriteLine($"You've got {sword.name}! It costs {sword.cost} rubles.");<p>Из-за того, что поле публичное, оно изменится:</p>
28 <p>Это плохо по нескольким причинам:</p>
28 <p>Это плохо по нескольким причинам:</p>
29 <ul><li>Если поле можно изменить в любом месте программы, сложно отслеживать ошибки, потому что не всегда понятно, где что-то пошло не так.</li>
29 <ul><li>Если поле можно изменить в любом месте программы, сложно отслеживать ошибки, потому что не всегда понятно, где что-то пошло не так.</li>
30 <li>Если вдруг в программу во время работы попадёт чужой код, он сможет изменять и читать любые поля любых объектов.</li>
30 <li>Если вдруг в программу во время работы попадёт чужой код, он сможет изменять и читать любые поля любых объектов.</li>
31 </ul><p>Разумеется, это не лучшее, что может случиться с приложением.</p>
31 </ul><p>Разумеется, это не лучшее, что может случиться с приложением.</p>
32 <p>Чтобы поля были защищены от вмешательства, используется ключевое слово private - оно делает члены класса доступными только внутри самого класса.</p>
32 <p>Чтобы поля были защищены от вмешательства, используется ключевое слово private - оно делает члены класса доступными только внутри самого класса.</p>
33 public class Item { private string name; private int cost; public Item(string name, int cost) { this.name = name; this.cost = cost; } }<p>Теперь эти поля нельзя будет изменить нигде, кроме как в методах этого класса. Но и получить их значение извне тоже не получится, а попытка вывести приведёт к ошибке:</p>
33 public class Item { private string name; private int cost; public Item(string name, int cost) { this.name = name; this.cost = cost; } }<p>Теперь эти поля нельзя будет изменить нигде, кроме как в методах этого класса. Но и получить их значение извне тоже не получится, а попытка вывести приведёт к ошибке:</p>
34 <p>Есть два способа сделать поле доступным только для чтения. Первый - использовать ключевое слово readonly, но оно запрещает менять значение вообще.</p>
34 <p>Есть два способа сделать поле доступным только для чтения. Первый - использовать ключевое слово readonly, но оно запрещает менять значение вообще.</p>
35 <p>Второй способ заключается в том, чтобы передавать значения приватного члена класса через публичный. Например, с помощью методов:</p>
35 <p>Второй способ заключается в том, чтобы передавать значения приватного члена класса через публичный. Например, с помощью методов:</p>
36 public string GetName() { return this.name; } public int GetCost() { return this.cost; }<p>К такой практике прибегают<a>Java-разработчики</a>, но в C# есть более элегантный способ - свойства.</p>
36 public string GetName() { return this.name; } public int GetCost() { return this.cost; }<p>К такой практике прибегают<a>Java-разработчики</a>, но в C# есть более элегантный способ - свойства.</p>
37 public string Name { //Объявление свойства. Свойства принято называть так же, как и поля, но начинаются они с заглавной буквы get //Конструкция get (также она называется геттером) позволяет определить логику получения значения { return this.name; } set //Конструкция set (сеттер) позволяет определить логику изменения значения { this.name = value; //value - это значение, которое передаётся свойству } }<p>Теперь, чтобы получить данные, нужно обратиться к свойству, а не к полю:</p>
37 public string Name { //Объявление свойства. Свойства принято называть так же, как и поля, но начинаются они с заглавной буквы get //Конструкция get (также она называется геттером) позволяет определить логику получения значения { return this.name; } set //Конструкция set (сеттер) позволяет определить логику изменения значения { this.name = value; //value - это значение, которое передаётся свойству } }<p>Теперь, чтобы получить данные, нужно обратиться к свойству, а не к полю:</p>
38 sword.Name = "Sword of Protection"; //Значения для свойства передаются так же, как и для обычной переменной Console.WriteLine($"You've got {sword.Name}!");<p>Преимущество этого в том, что можно разрешить получать данные, но запретить их менять. То есть прописать только геттер:</p>
38 sword.Name = "Sword of Protection"; //Значения для свойства передаются так же, как и для обычной переменной Console.WriteLine($"You've got {sword.Name}!");<p>Преимущество этого в том, что можно разрешить получать данные, но запретить их менять. То есть прописать только геттер:</p>
39 <p>Обратите внимание, что можно просто написать set; или get; если не требуется дополнительная логика. Это сработает, если у поля и свойства одинаковые имена и если это примитивный тип (int, float, char, double и другие). Со ссылочными типами (объекты и строки) это не работает.</p>
39 <p>Обратите внимание, что можно просто написать set; или get; если не требуется дополнительная логика. Это сработает, если у поля и свойства одинаковые имена и если это примитивный тип (int, float, char, double и другие). Со ссылочными типами (объекты и строки) это не работает.</p>
40 <p>Также можно менять логику работы со значением:</p>
40 <p>Также можно менять логику работы со значением:</p>
41 public int Cost { get { return this.cost; } set { if(value &gt; 0) { this.cost = value; } } }<p>Здесь поле будет изменено только в том случае, если ему пытаются указать значение, которое выше нуля.</p>
41 public int Cost { get { return this.cost; } set { if(value &gt; 0) { this.cost = value; } } }<p>Здесь поле будет изменено только в том случае, если ему пытаются указать значение, которое выше нуля.</p>
42 <p>То есть если запустить вот такой код:</p>
42 <p>То есть если запустить вот такой код:</p>
43 sword.Cost = 50; sword.Cost = -1; Console.WriteLine($"Sword's cost: {sword.Cost}!");<p>То выведено будет 50, а не -1:</p>
43 sword.Cost = 50; sword.Cost = -1; Console.WriteLine($"Sword's cost: {sword.Cost}!");<p>То выведено будет 50, а не -1:</p>
44 <p>Также можно создавать свойства без поля:</p>
44 <p>Также можно создавать свойства без поля:</p>
45 public bool IsExpensive { get { if(this.cost &gt; 5000) { return true; } else { return false; } } }<p>Это свойство вернёт true, если цена выше 5000, и false, если ниже.</p>
45 public bool IsExpensive { get { if(this.cost &gt; 5000) { return true; } else { return false; } } }<p>Это свойство вернёт true, если цена выше 5000, и false, если ниже.</p>
46 <p>Ключевое слово private можно также применять и к методам. Это делает их доступными только внутри класса.</p>
46 <p>Ключевое слово private можно также применять и к методам. Это делает их доступными только внутри класса.</p>
47 private void Wipe() { this.name = ""; this.cost = 0; }<p>Также приватным можно сделать сам класс, если он находится внутри другого класса:</p>
47 private void Wipe() { this.name = ""; this.cost = 0; }<p>Также приватным можно сделать сам класс, если он находится внутри другого класса:</p>
48 public class Char { private Collider collider = new Collider(); private class Collider { public int x = 5; public int y = 10; public int width = 15; public int height = 25; } }<p>Иногда нужно сделать компонент доступным только внутри одного файла - например, в Program.cs, Item.cs или любом другом. Для этого используется ключевое слово internal.</p>
48 public class Char { private Collider collider = new Collider(); private class Collider { public int x = 5; public int y = 10; public int width = 15; public int height = 25; } }<p>Иногда нужно сделать компонент доступным только внутри одного файла - например, в Program.cs, Item.cs или любом другом. Для этого используется ключевое слово internal.</p>
49 class Program { static void Main(string[] args) { Backpack b = new Backpack(); Console.WriteLine($"{b.itemsCount} items in the backpack."); } } internal class Backpack { public int itemsCount = 10; }<p>Класс<em>Backpack</em>можно будет использовать только внутри файла Program.cs, и попытка объявить его внутри другого файла приведёт к ошибке.</p>
49 class Program { static void Main(string[] args) { Backpack b = new Backpack(); Console.WriteLine($"{b.itemsCount} items in the backpack."); } } internal class Backpack { public int itemsCount = 10; }<p>Класс<em>Backpack</em>можно будет использовать только внутри файла Program.cs, и попытка объявить его внутри другого файла приведёт к ошибке.</p>
50 <p>Статичность относится не совсем к уровням доступа, но тоже помогает заключить реализацию функционала в оболочку класса. Статичность позволяет обращаться к методам или полям, не создавая объект.</p>
50 <p>Статичность относится не совсем к уровням доступа, но тоже помогает заключить реализацию функционала в оболочку класса. Статичность позволяет обращаться к методам или полям, не создавая объект.</p>
51 <p>Например:</p>
51 <p>Например:</p>
52 class Program { static void Main(string[] args) { Console.WriteLine($"5 + 6 = {Calc.Sum(5, 6)}"); } } class Calc { public static int Sum(int a, int b) //Создание статичного метода { return a + b; } }<p>Метод Sum () используется в классе Program, хотя экземпляр класса Calc не создавался. При этом можно сделать статичным как отдельный метод или свойство, так и весь класс. В этом случае все поля и методы тоже должны быть статичными.</p>
52 class Program { static void Main(string[] args) { Console.WriteLine($"5 + 6 = {Calc.Sum(5, 6)}"); } } class Calc { public static int Sum(int a, int b) //Создание статичного метода { return a + b; } }<p>Метод Sum () используется в классе Program, хотя экземпляр класса Calc не создавался. При этом можно сделать статичным как отдельный метод или свойство, так и весь класс. В этом случае все поля и методы тоже должны быть статичными.</p>
53 <p>Это может быть нужно, чтобы создать набор инструментов, который будет использоваться в других частях программы. Хороший пример - класс Console, который тоже является статичным.</p>
53 <p>Это может быть нужно, чтобы создать набор инструментов, который будет использоваться в других частях программы. Хороший пример - класс Console, который тоже является статичным.</p>
54 <p>Другой пример - класс Math. Его можно использовать, чтобы выполнять различные математические операции (получение квадратного корня, модуляция, получение синуса, косинуса и так далее). У него много методов, а также он хранит различные константы вроде числа пи.</p>
54 <p>Другой пример - класс Math. Его можно использовать, чтобы выполнять различные математические операции (получение квадратного корня, модуляция, получение синуса, косинуса и так далее). У него много методов, а также он хранит различные константы вроде числа пи.</p>
55 <p>Подробно о том, что такое классы и объекты, читайте в<a>первой статье</a>цикла об объектно-ориентированном программировании.</p>
55 <p>Подробно о том, что такое классы и объекты, читайте в<a>первой статье</a>цикла об объектно-ориентированном программировании.</p>
56 <p>Напишите класс GameObject, в котором будут храниться координаты объекта. Координаты должны быть доступны для чтения, а их изменение должно происходить в методе Move ().</p>
56 <p>Напишите класс GameObject, в котором будут храниться координаты объекта. Координаты должны быть доступны для чтения, а их изменение должно происходить в методе Move ().</p>
57 <p>Есть и другие ключевые слова:</p>
57 <p>Есть и другие ключевые слова:</p>
58 <ul><li>abstract;</li>
58 <ul><li>abstract;</li>
59 <li>protected;</li>
59 <li>protected;</li>
60 <li>private protected;</li>
60 <li>private protected;</li>
61 <li>protected internal;</li>
61 <li>protected internal;</li>
62 <li>sealed и другие.</li>
62 <li>sealed и другие.</li>
63 </ul><p>Они будут рассмотрены в статье о наследовании.</p>
63 </ul><p>Они будут рассмотрены в статье о наследовании.</p>
64 <a><b>Бесплатный курс по Python ➞</b>Мини-курс для новичков и для опытных кодеров. 4 крутых проекта в портфолио, живое общение со спикером. Кликните и узнайте, чему можно научиться на курсе. Смотреть программу</a>
64 <a><b>Бесплатный курс по Python ➞</b>Мини-курс для новичков и для опытных кодеров. 4 крутых проекта в портфолио, живое общение со спикером. Кликните и узнайте, чему можно научиться на курсе. Смотреть программу</a>