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>24 янв 2020</li>
2
<ul><li>24 янв 2020</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>В<a>предыдущей статье</a>мы увидели, насколько удобнее становится ООП благодаря наследованию. Но оно может стать ещё лучше, если использовать абстрактные классы и интерфейсы.</p>
7
<p>В<a>предыдущей статье</a>мы увидели, насколько удобнее становится ООП благодаря наследованию. Но оно может стать ещё лучше, если использовать абстрактные классы и интерфейсы.</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><strong>В широком смысле абстракция</strong> - это когда мы фокусируемся на тех свойствах системы, которые важны в рамках текущей задачи, а менее существенные отбрасываем.</p>
16
</ul><p><strong>В широком смысле абстракция</strong> - это когда мы фокусируемся на тех свойствах системы, которые важны в рамках текущей задачи, а менее существенные отбрасываем.</p>
17
<p>Абстракции часто встречаются в повседневной жизни. Например, когда мы набираем и отправляем сообщения в мессенджере, то работаем лишь с клавиатурой и кнопкой "Отправить". Мы не задумываемся о версии приложения, о том, какую кодировку использует операционная система, сколько весит наше сообщение и т.д.</p>
17
<p>Абстракции часто встречаются в повседневной жизни. Например, когда мы набираем и отправляем сообщения в мессенджере, то работаем лишь с клавиатурой и кнопкой "Отправить". Мы не задумываемся о версии приложения, о том, какую кодировку использует операционная система, сколько весит наше сообщение и т.д.</p>
18
<p>Другой пример - вождение автомобиля. Водитель думает лишь о том, куда поворачивать руль и когда нажимать педали. Он не задумывается о том, какого цвета его автомобиль, из какого материала сделана обивка салона, сколько присадок в моторном масле, и прочих вещах, которые не влияют на процесс вождения.</p>
18
<p>Другой пример - вождение автомобиля. Водитель думает лишь о том, куда поворачивать руль и когда нажимать педали. Он не задумывается о том, какого цвета его автомобиль, из какого материала сделана обивка салона, сколько присадок в моторном масле, и прочих вещах, которые не влияют на процесс вождения.</p>
19
<p>Похожая ситуация в объектно-ориентированном программировании, только там мы имеем дело с абстракцией данных и методов. Например, чтобы рассчитать зависимость количества потребляемого топлива от веса автомобиля, нам достаточно использовать атрибуты "вес" и "номер" (чтобы различать автомобили) и метод "ехать" (для моделирования пробега).</p>
19
<p>Похожая ситуация в объектно-ориентированном программировании, только там мы имеем дело с абстракцией данных и методов. Например, чтобы рассчитать зависимость количества потребляемого топлива от веса автомобиля, нам достаточно использовать атрибуты "вес" и "номер" (чтобы различать автомобили) и метод "ехать" (для моделирования пробега).</p>
20
class Car { private string id_number; private int weight; //константа пути (100 км) private int const distance = 100; public Car(string id_number, int weight){ this.id_number = id_number; this.weight = weight; } int Go(){ //формула для расчета количества потребляемого топлива } };<p>Конечно, реальные автомобили отличаются цветом, габаритами, размером колес, типом шин, материалом обивки салона и т.д. А еще они умеют не только ехать, но и заводиться, тормозить и глохнуть. Но все эти подробности не имеют отношения к поставленной задаче, а значит, мы можем их смело опустить.</p>
20
class Car { private string id_number; private int weight; //константа пути (100 км) private int const distance = 100; public Car(string id_number, int weight){ this.id_number = id_number; this.weight = weight; } int Go(){ //формула для расчета количества потребляемого топлива } };<p>Конечно, реальные автомобили отличаются цветом, габаритами, размером колес, типом шин, материалом обивки салона и т.д. А еще они умеют не только ехать, но и заводиться, тормозить и глохнуть. Но все эти подробности не имеют отношения к поставленной задаче, а значит, мы можем их смело опустить.</p>
21
<p><strong>Абстрактные классы в объектно-ориентированном программировании</strong> - это базовые классы, которые можно наследовать, но нельзя реализовывать. То есть на их основе нельзя создать объект.</p>
21
<p><strong>Абстрактные классы в объектно-ориентированном программировании</strong> - это базовые классы, которые можно наследовать, но нельзя реализовывать. То есть на их основе нельзя создать объект.</p>
22
<p>Пример такого класса из жизни - животное. Рыбы, пауки и насекомые являются животными, но каждое из них также принадлежит своему подклассу с набором специфических свойств. При этом, просто "животных" в природе не существует.</p>
22
<p>Пример такого класса из жизни - животное. Рыбы, пауки и насекомые являются животными, но каждое из них также принадлежит своему подклассу с набором специфических свойств. При этом, просто "животных" в природе не существует.</p>
23
<p>В программировании абстрактные классы могут понадобиться, чтобы объединить реализацию нескольких схожих классов. Например, в вашей игре должны быть персонаж игрока и NPC<em>(неигровые персонажи).</em>У них могут быть общие свойства<em>(имя, координаты)</em>и методы<em>(перемещение, изменение анимации)</em>.</p>
23
<p>В программировании абстрактные классы могут понадобиться, чтобы объединить реализацию нескольких схожих классов. Например, в вашей игре должны быть персонаж игрока и NPC<em>(неигровые персонажи).</em>У них могут быть общие свойства<em>(имя, координаты)</em>и методы<em>(перемещение, изменение анимации)</em>.</p>
24
<p>Чтобы не повторять код несколько раз, можно вынести реализацию этих свойств и методов в абстрактный класс<strong>Character</strong>. Для его объявления используют ключевое слово<strong><strong>abstract</strong></strong>:</p>
24
<p>Чтобы не повторять код несколько раз, можно вынести реализацию этих свойств и методов в абстрактный класс<strong>Character</strong>. Для его объявления используют ключевое слово<strong><strong>abstract</strong></strong>:</p>
25
abstract class Character { private string name; private int x; public int y; public Character(string name, int x, int y) { this.name = name; this.x = x; this.y = y; } public int X { get { return this.x; } } public void ShowName() { Console.WriteLine(this.name); } public abstract int Y { get; } public abstract void ShowPosition(); }<p>Тут всё как у обычных классов, но в конце можно заметить объявление свойства и метода без реализации. Реализация этих абстрактных свойств должна находиться в дочернем классе:</p>
25
abstract class Character { private string name; private int x; public int y; public Character(string name, int x, int y) { this.name = name; this.x = x; this.y = y; } public int X { get { return this.x; } } public void ShowName() { Console.WriteLine(this.name); } public abstract int Y { get; } public abstract void ShowPosition(); }<p>Тут всё как у обычных классов, но в конце можно заметить объявление свойства и метода без реализации. Реализация этих абстрактных свойств должна находиться в дочернем классе:</p>
26
class Player : Character { public Player(string name, int x, int y) :base(name, x, y) { } public override int Y { get { return this.y; } } public override void ShowPosition() { Console.WriteLine($"[{X}, {Y}]"); } }<p>Когда объявляется реализация такого члена класса, необходимо указать ключевое слово<strong>override.</strong>Абстрактными могут быть следующие члены класса:</p>
26
class Player : Character { public Player(string name, int x, int y) :base(name, x, y) { } public override int Y { get { return this.y; } } public override void ShowPosition() { Console.WriteLine($"[{X}, {Y}]"); } }<p>Когда объявляется реализация такого члена класса, необходимо указать ключевое слово<strong>override.</strong>Абстрактными могут быть следующие члены класса:</p>
27
<ul><li>методы;</li>
27
<ul><li>методы;</li>
28
<li>свойства;</li>
28
<li>свойства;</li>
29
<li>индексаторы;</li>
29
<li>индексаторы;</li>
30
<li>события.</li>
30
<li>события.</li>
31
</ul><p>Дочерний класс должен реализовывать все члены родительского абстрактного класса, кроме тех случаев, когда дочерний класс тоже абстрактный.</p>
31
</ul><p>Дочерний класс должен реализовывать все члены родительского абстрактного класса, кроме тех случаев, когда дочерний класс тоже абстрактный.</p>
32
<p>В остальном всё очень похоже на обычные классы. Например, поле<strong>Y</strong>класса Character публичное, чтобы можно было использовать его в свойстве<strong>Y</strong>дочерних классов.</p>
32
<p>В остальном всё очень похоже на обычные классы. Например, поле<strong>Y</strong>класса Character публичное, чтобы можно было использовать его в свойстве<strong>Y</strong>дочерних классов.</p>
33
<p><strong>Важно!</strong></p>
33
<p><strong>Важно!</strong></p>
34
<p><strong>Абстрактный класс должен быть публичным.</strong></p>
34
<p><strong>Абстрактный класс должен быть публичным.</strong></p>
35
<p>Интерфейс похож на абстрактный класс: вы так же не можете объявить его экземпляр, дочерний класс должен реализовывать все члены интерфейса. Реализация членов может находиться как в интерфейсе, так и в дочернем классе.</p>
35
<p>Интерфейс похож на абстрактный класс: вы так же не можете объявить его экземпляр, дочерний класс должен реализовывать все члены интерфейса. Реализация членов может находиться как в интерфейсе, так и в дочернем классе.</p>
36
<p>Сходств очень много, но у интерфейсов есть особенность: один класс может наследовать несколько интерфейсов сразу.</p>
36
<p>Сходств очень много, но у интерфейсов есть особенность: один класс может наследовать несколько интерфейсов сразу.</p>
37
<p>Объявляется интерфейс следующим образом:</p>
37
<p>Объявляется интерфейс следующим образом:</p>
38
//Используется ключевое слово interface interface IInteractive //Названия интерфейсов принято начинать с заглавной буквы I { void Interact(Player p); //Метод без реализации //public bool Accessor { get; set; } //Доступно начиная с C# 8.0 bool IsInteractive() //Метод с реализацией { return true; } //const bool Interactive = true; //Константы //static bool Enabled = true; //Статические поля //Поля объявлять нельзя }<p>Также можно использовать индексаторы и события<em>(это тема для отдельной статьи).</em>Теперь рассмотрим применение этого интерфейса.</p>
38
//Используется ключевое слово interface interface IInteractive //Названия интерфейсов принято начинать с заглавной буквы I { void Interact(Player p); //Метод без реализации //public bool Accessor { get; set; } //Доступно начиная с C# 8.0 bool IsInteractive() //Метод с реализацией { return true; } //const bool Interactive = true; //Константы //static bool Enabled = true; //Статические поля //Поля объявлять нельзя }<p>Также можно использовать индексаторы и события<em>(это тема для отдельной статьи).</em>Теперь рассмотрим применение этого интерфейса.</p>
39
class NPC : Character, IInteractive { public NPC(string name, int x, int y) :base(name, x, y) { } public override int Y { get { return this.y; } } public override void ShowPosition() { Console.WriteLine($"[{X}, {Y}]"); } public void Interact(Player p) { Console.WriteLine($"{p.Name} interacting with {this.Name}"); } }<p>В отличие от абстрактных методов, методы интерфейса не нужно реализовывать с ключевым словом<strong>override.</strong></p>
39
class NPC : Character, IInteractive { public NPC(string name, int x, int y) :base(name, x, y) { } public override int Y { get { return this.y; } } public override void ShowPosition() { Console.WriteLine($"[{X}, {Y}]"); } public void Interact(Player p) { Console.WriteLine($"{p.Name} interacting with {this.Name}"); } }<p>В отличие от абстрактных методов, методы интерфейса не нужно реализовывать с ключевым словом<strong>override.</strong></p>
40
<p>Также есть одна особенность: метод, реализация которого находится внутри интерфейса, не может использовать этот метод - класс нужно привести к интерфейсу. Для примера добавим в класс<em><strong>Player</strong></em>следующий метод:</p>
40
<p>Также есть одна особенность: метод, реализация которого находится внутри интерфейса, не может использовать этот метод - класс нужно привести к интерфейсу. Для примера добавим в класс<em><strong>Player</strong></em>следующий метод:</p>
41
public void Interact(IInteractive obj) { if(obj.IsInteractive()) { obj.Interact(this); } }<p>В качестве параметра в этот метод можно передавать любой класс, который использует интерфейс<em><strong>IInteractive</strong></em>.</p>
41
public void Interact(IInteractive obj) { if(obj.IsInteractive()) { obj.Interact(this); } }<p>В качестве параметра в этот метод можно передавать любой класс, который использует интерфейс<em><strong>IInteractive</strong></em>.</p>
42
Player p = new Player("Gamer", 5, 10); NPC npc = new NPC("Cube", 10, 10); p.Interact(npc);<p>Это очень удобно в разработке игр, в которых взаимодействовать можно с самыми разными объектами - от NPC до предметов.</p>
42
Player p = new Player("Gamer", 5, 10); NPC npc = new NPC("Cube", 10, 10); p.Interact(npc);<p>Это очень удобно в разработке игр, в которых взаимодействовать можно с самыми разными объектами - от NPC до предметов.</p>
43
<p>Более подробно об отличиях интерфейсов и абстрактных классов на примерах из Java можно прочитать в <a>другой нашей статье</a>.</p>
43
<p>Более подробно об отличиях интерфейсов и абстрактных классов на примерах из Java можно прочитать в <a>другой нашей статье</a>.</p>
44
<p>Создайте игру, в которой будут использоваться абстрактные классы<em>Character</em>и<em>Item</em>, а также интерфейсы<em>IInteractive, ITalkable, IMovable.</em>Методы и свойства придумайте, исходя из названий.</p>
44
<p>Создайте игру, в которой будут использоваться абстрактные классы<em>Character</em>и<em>Item</em>, а также интерфейсы<em>IInteractive, ITalkable, IMovable.</em>Методы и свойства придумайте, исходя из названий.</p>
45
<p>Вот мы и рассмотрели основные части объектно-ориентированного программирования. Дальше вас ждёт практикум, в котором мы поработаем над полноценным проектом, чтобы закрепить полученные знания и узнать ещё немного полезностей.</p>
45
<p>Вот мы и рассмотрели основные части объектно-ориентированного программирования. Дальше вас ждёт практикум, в котором мы поработаем над полноценным проектом, чтобы закрепить полученные знания и узнать ещё немного полезностей.</p>
46
<a><b>Бесплатный курс по Python ➞</b>Мини-курс для новичков и для опытных кодеров. 4 крутых проекта в портфолио, живое общение со спикером. Кликните и узнайте, чему можно научиться на курсе. Смотреть программу</a>
46
<a><b>Бесплатный курс по Python ➞</b>Мини-курс для новичков и для опытных кодеров. 4 крутых проекта в портфолио, живое общение со спикером. Кликните и узнайте, чему можно научиться на курсе. Смотреть программу</a>