Введение в ООП с примерами на C#. Часть первая. Все, что нужно знать о полиморфизме
Гайд для новичков — что такое ООП, полиморфизм и параметры и как написать код
153К открытий156К показов
Рассказывает Akhil Mittal
Я много писал на смежные темы, вроде концепции MVC, Entity Framework, паттерна «Репозиторий» и т.п. Моим приоритетом всегда было полное раскрытие темы, чтобы читателю не приходилось гуглить недостающие детали. Этот цикл статей опишет абсолютно все концепции ООП, которые могут интересовать начинающих разработчиков. Однако эта статья предназначена не только для тех, кто начинает свой путь в программировании: она написана и для опытных программистов, которым может потребоваться освежить свои знания.
Сразу скажу, далеко в теорию мы вдаваться не будем — нас интересуют специфичные вопросы. Где это будет нужно, я буду сопровождать повествование кодом на C#.
Что такое ООП и в чём его плюсы?
«ООП» значит «Объектно-Ориентированное Программирование». Это такой подход к написанию программ, который основывается на объектах, а не на функциях и процедурах. Эта модель ставит в центр внимания объекты, а не действия, данные, а не логику. Объект — реализация класса. Все реализации одного класса похожи друг на друга, но могут иметь разные параметры и значения. Объекты могут задействовать методы, специфичные для них.
ООП сильно упрощает процесс организации и создания структуры программы. Отдельные объекты, которые можно менять без воздействия на остальные части программы, упрощают также и внесение в программу изменений. Так как с течением времени программы становятся всё более крупными, а их поддержка всё более тяжёлой, эти два аспекта ООП становятся всё более актуальными.
Что за концепции ООП?
Сейчас коротко о принципах, которые мы позже рассмотрим в подробностях:
- Абстракция данных: подробности внутренней логики скрыты от конечного пользователя. Пользователю не нужно знать, как работают те или иные классы и методы, чтоб их использовать. Подходящим примером из реальной жизни будет велосипед — когда мы ездим на нём или меняем деталь, нам не нужно знать, как педаль приводит его в движение или как закреплена цепь.
- Наследование: самый популярный принцип ООП. Наследование делает возможным повторное использование кода — если какой-то класс уже имеет какую-то логику и функции, нам не нужно переписывать всё это заново для создания нового класса, мы можем просто включить старый класс в новый, целиком.
- Инкапсуляция: включение в класс объектов другого класса, вопросы доступа к ним, их видимости.
- Полиморфизм: «поли» значит «много», а «морфизм» — «изменение» или «вариативность», таким образом, «полиморфизм» — это свойство одних и тех же объектов и методов принимать разные формы.
- Обмен сообщениями: способность одних объектов вызывать методы других объектов, передавая им управление.
Ладно, тут мы коснулись большого количества теории, настало время действовать. Я надеюсь, это будет интересно.
Полиморфизм
В этой статье мы рассмотрим буквально все сценарии использования полиморфизма, использование параметров и разные возможные типы мышления во время написания кода.
Перегрузка методов
1. Давайте создадим консольное приложение InheritanceAndPolymorphism
и класс Overload.cs
с тремя методами DisplayOverload
с параметрами, как ниже:
В главном методе Program.cs
теперь напишем следующее:
И теперь, когда мы это запустим, вывод будет следующим:
Класс Overload
содержит три метода, и все они называются DisplayOverload
, они различаются только типами параметров. В C# (как и в большистве других языков) мы можем создавать методы с одинаковыми именами, но разными параметрами, это и называется «перегрузка методов». Это значит, что нам нет нужды запоминать кучу имён методов, которые совершают одинаковые действия с разными типами данных.Что нужно запомнить: метод идентифицируется не только по имени, но и по его параметрам.
2. Если же мы запустим следующий код:
Мы получим ошибку компиляции:
Здесь вы можете видеть две функции, которые различаются только по возвращаемому типу, и скомпилировать это нельзя. Что нужно запомнить: метод не идентифицируется по возвращаемому типу, это не полиморфизм.
3. Если мы попробуем скомпилировать:
У нас это тоже не получится:
Здесь присутствуют два метода, принимающих целое число в качестве аргумента, с той лишь разницей, что один из них помечен как статический. Что нужно запомнить: модификаторы вроде static также не являются свойствами, идентифицирующими метод.
4. Если мы запустим нижеследующий код в надежде, что теперь-то идентификаторы у методов будут разными:
То нас опять ждёт разочарование:
Что нужно запомнить: на идентификатор метода оказывают влияние только его имя и параметры (их тип, количество). Модификаторы доступа не влияют. Двух методов с одинаковыми идентификаторами существовать не может.
Роль ключевого слова params в полиморфизме
Параметры могут быть четырёх разных видов:
- переданное значение;
- переданная ссылка;
- параметр для вывода;
- массив параметров.
С первыми тремя мы, вроде, разобрались, теперь подробнее взглянем на четвёртый.
- Если мы запустим следующий код:
То получим две ошибки:
Отсюда следуют вывод: имена параметров должны быть уникальны. Также не могут быть одинаковыми имя параметра метода и имя переменной, созданной в этом же методе.
- Теперь попробуем запустить следующий код:
Мы получим следующий вывод:
Мы можем передавать одинаковые ссылочные параметры столько раз, сколько захотим. В методе Display
строка name
имеет значение «Akhil». Когда мы меняем значение x
на «Akhil1», на самом деле мы меняем значение name
, т.к. через параметр x
передана ссылка именно на него. То же и с y
— все эти три переменных ссылаются на одно место в памяти.
- Теперь самое интересное:
Это даст нам такой вывод:
Нам часто может потребоваться передать методу n параметров. В C# такую возможность предоставляет ключевое слово params
.
Важно: это ключевое слово может быть применено только к последнему аргументу метода, так что метод ниже работать не будет:
1. В случае DisplayOverload
первый аргумент должен быть целым числом, а остальные — сколь угодно много строк или наоборот, ни одной.
Вывод: 200 100300 100100 200
Важно запомнить: C# достаточно умён, чтоб разделить обычные параметры и массив параметров, даже если они одного типа.
2. Посмотрите на следующие два метода:
Разница между ними в том, что первый запустится, и такая синтаксическая конструкция будет подразумевать, что в метод будет передаваться n массивов строк. Вторая же выдаст ошибку:
Запомните: массив параметров должен быть одномерным.
3. Следует упомянуть, что последний аргумент не обязательно заполнять отдельными объектами, можно его использовать, будто это обычный аргумент, принимающий массив, то есть:
Вывод будет следующим:
Однако такой код:
Уже вызовет ошибку:
Думаю, тут всё понятно — или, или. Смешивать передачу отдельными параметрами и одним массивом нельзя.
- Теперь рассмотрим поведение следующей программы:
После её выполнения мы получим в консоли: 1000
Это происходит из-за того, что при подобном синтаксисе массив передаётся по ссылке. Однако стоит отметить следующую особенность:
Результатом выполнения такого кода будет
102
Ведь из переданных параметров C# автоматически формирует новый, временный массив.
- Теперь поговорим о приоритете языка в выборе методов. Предположим, у нас есть такой код:
C# рассматривает методы с массивом параметров последними, так что во втором случае будет вызван метод, принимающий два целых числа. В первом и третьем случае будет вызван метод с params
, так как ничего кроме него запустить невозможно. Таким образом, на выходе мы получим:
- Теперь кое-что интересное. Как вы думаете, каким будет результат выполнения следующей программы?
В консоли мы увидим:
То есть, в первом и в четвёртом случаях массив передаётся именно как массив, заменяя собой objectParamArray
, а во втором и третьем случаях массив передаётся как единичный объект, из которого создаётся новый массив из одного элемента.
В заключение
В этой статье мы рассмотрели перегрузку методов, особенности компиляции, с ней связанные, и буквально все возможные случаи использования ключевого слова params
. В следующей мы рассмотрим наследование. Напоследок ещё раз повторим основные пункты, которые нужно запомнить:
- Метод идентифицируется не только по имени, но и по его параметрам.
- Метод не идентифицируется по возвращаемому типу.
- Модификаторы вроде
static
также не являются свойствами, идентифицирующими метод. - На идентификатор метода оказывают влияние только его имя и параметры (их тип, количество). Модификаторы доступа не влияют. Двух методов с одинаковыми идентификаторами существовать не может.
- Имена параметров должны быть уникальны. Также не могут быть одинаковыми имя параметра метода и имя переменной, созданной в этом же методе.
- Ключевое слово
params
может быть применено только к последнему аргументу метода. - C# достаточно умён, чтоб разделить обычные параметры и массив параметров, даже если они одного типа.
- Массив параметров должен быть одномерным.
153К открытий156К показов