Полиморфизм в языке Dart

Начнём с определения в википедии:

Полиморфизм в языках программирования и теории типов — способность функции обрабатывать данные разных типов

Существует два вида полиморфизма 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);
}

Вывод в консоли

fd3ab925ac4216c977b8474c10414fc3.png

Всё отработало правильно. Наш ChildrenEnglishTeacher переопределил метод hasLessonsToday от вышестоящего класса EnglishTeacher и так же переопределил слегка изменённый сеттор age от базового класса Teacher.

Итак, определение полиморфизма можно дать более понятными словами (после примера).

Принцип полиморфизма в ООП (объектно-ориентированном программировании) предполагает использование одного и того же имени метода или свойства для объектов разных классов. Иными словами, полиморфизм позволяет обращаться к объектам разных классов с помощью одних и тех же методов или свойств.

Зачем нам полиморфизм?

Прежде всего, чтоб убрать дублирование кода, улучшить читаемость и для удобного масштабирования.

© Habrahabr.ru