Начнём с определения в википедии:
Полиморфизм в языках программирования и теории типов — способность функции обрабатывать данные разных типов
Существует два вида полиморфизма ad-hoc (он же мнимый) и параметрический (он же истинный). Язык Dart не поддерживает перегрузку (overloading) метода поэтому обсуждать ad-hoc нет смысла. Переходим к параметрическому полиморфизму и сразу смотрим на примере.
Создадим класс Teacher с 2-мя свойствами yearExpiriance - опыт в годах и birthYear - год рождение. Метод study где будем возвращать текст - Я уже обучаю студентов Х лет. А так же сеттор age - с помощью него будем устанавливать новую дату рождения и геттер - будем определять на сколько большой опыт преподавания у учителя.
class Teacher {
final int yearExperience;
late int yearBirth;
Teacher({required this.yearExperience, required this.yearBirth});
String study() {
return 'I am teacher';
}
// Раскоментируйте, чтоб убедиться что перегрузку методов Дарт не поддерживает.
// Вы получите ошибку - The name 'study' is already defined.
// String study(int any) {
// return 'I study my students for $yearBirth';
// }
set age(int val) => yearBirth = (DateTime.now().year - val);
String get isBigExpiriance => yearExperience >= 10
? 'Опыт больше или равен 10 лет'
: 'Опыт меньше 10 лет';
}
Полиморфизм в ООП не может существовать без наследования!
Создаём два класса, EnglishTeacher - учитель английского языка, который будет наследоваться от Teacher и класс ChildrenEnglishTeacher (детский учитель английского языка), который будет наследоваться от EnglishTeacher.
import 'package:flutter_application_1/teacher.dart';
class EnglishTeacher extends Teacher {
EnglishTeacher({required super.yearExperience, required super.yearBirth});
// Переопределяем метод базового класса.
@override
String study() {
return 'I have been teaching my students for $yearExperience years';
}
String hasLessonsToday() {
return 'Yes. I have lesson today';
}
// Переопределяем метод базового класса.
@override
String get isBigExpiriance => yearExperience >= 5
? 'Большой опыт'
: 'Опыт учителя английского языка $yearExperience года';
}
Класс EnglishTeacher с помощью @override переопределяет метод study базового класса (Teacher) и будет возвращать другой текст, специфичный для учителя английского языка (Я обучаю моих студентов уже Х лет). А так же EnglishTeacher имеет собственный метод hasLessonsToday, который отвечает на вопрос: "Есть ли сегодня занятия?" и будет возвращать - "Да. Сегодня будет занятие". А так же мы, переопределили геттор isBigExpiriance, где изменили условия и тексты.
Класс ChildrenEnglishTeacher мы создадим, просто для того чтоб было понимание что можно построить иерархию классов, где каждый последующий класс будет наследоваться от вышестоящиего. И в самом нижнем классе всегда можно переопределить методы из всех вышестоящих в плоть то самого верхнего (базового Teacher). То есть метод hasLessons есть в классе EnglishTeacher, но его нет в базовом классе (самый верхний -Teacher).
А так же у нас есть возможность переопределить сеттор age который есть у самого верхнего базового класса Teacher.
import 'package:flutter_application_1/english_teacher.dart';
class ChildrenEnglishTeacher extends EnglishTeacher {
ChildrenEnglishTeacher(
{required super.yearExperience, required super.yearBirth});
@override
String hasLessonsToday() {
return 'No. I have not';
}
@override
set age(int val) => yearBirth = (DateTime.now().year - val - 3);
}
Теперь приступим к проверке, в функции main сделаем инстанс EnglishTeacher и запустим оба унаследованных от базового класса метода
void main() {
final englishTeacher = EnglishTeacher(yearExperience: 5, yearBirth: 1970);
print(englishTeacher.study());
print(englishTeacher.isBigExpiriance);
}
Вывод в консоль
И проверим наш самый низший класс наследник ChildrenEnglishTeacher
void main() {
final childrenEnglishTeacher =
ChildrenEnglishTeacher(yearExperience: 6, yearBirth: 1920);
childrenEnglishTeacher.age = 30;
print(childrenEnglishTeacher.hasLessonsToday());
print(childrenEnglishTeacher.yearBirth);
}
Вывод в консоли
Всё отработало правильно. Наш ChildrenEnglishTeacher переопределил метод hasLessonsToday от вышестоящего класса EnglishTeacher и так же переопределил слегка изменённый сеттор age от базового класса Teacher.
Итак, определение полиморфизма можно дать более понятными словами (после примера).
Принцип полиморфизма в ООП (объектно-ориентированном программировании) предполагает использование одного и того же имени метода или свойства для объектов разных классов. Иными словами, полиморфизм позволяет обращаться к объектам разных классов с помощью одних и тех же методов или свойств.
Зачем нам полиморфизм?
Прежде всего, чтоб убрать дублирование кода, улучшить читаемость и для удобного масштабирования.