Аннотация @override
Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy — урок 39 из 110.
Аннотация @override — это маркер передовой практики, который сообщает Dart (и другим разработчикам), что вы намеренно заменяете метод родительского класса. Хотя переопределение методов работает и без неё, использование @override создает важную подстраховку.
class Animal {
String name;
Animal(this.name);
void speak() {
print('$name makes a sound');
}
}
class Dog extends Animal {
Dog(String name) : super(name);
@override
void speak() {
print('$name barks: Woof!');
}
}Аннотация дает два ключевых преимущества. Во-первых, она четко документирует ваше намерение — любой, кто читает код, сразу понимает, что этот метод существует в родительском классе. Во-вторых, анализатор Dart предупредит вас, если родительский метод на самом деле не существует, что позволяет на ранней стадии обнаружить опечатки и ошибки рефакторинга.
Рассмотрим, что произойдет, если вы неправильно напишете имя метода без @override:
class Cat extends Animal {
Cat(String name) : super(name);
void speek() { // Опечатка! Нет предупреждения без @override
print('$name meows');
}
}Без аннотации Dart предполагает, что вы создаете новый метод с именем speek(). С @override анализатор немедленно сообщит о том, что такого метода не существует в родительском классе. Эта простая аннотация предотвращает неявные ошибки, которые может быть трудно отследить позже.
Задание
ЛегкоДавайте создадим систему медиаплеера, которая продемонстрирует важность аннотации @override при настройке унаследованного поведения. Вы создадите различные типы медиа, каждый из которых воспроизводит контент по-своему.
Вы организуете свой код в два файла:
media.dart: Определите здесь иерархию медиа:- Класс
Mediaсо свойствомString title, конструктором, принимающим заголовок, и методомplay(), который выводитPlaying: [title] - Класс
Song, который расширяетMediaи добавляет свойствоString artist. Используйте аннотацию@overrideи переопределитеplay(), чтобы вывестиPlaying song: [title] by [artist] - Класс
Video, который расширяетMediaи добавляет свойствоint duration(в секундах). Используйте@overrideи переопределитеplay(), чтобы сначала вызвать родительскую версию с помощьюsuper.play(), а затем вывестиDuration: [duration] seconds
- Класс
main.dart: Импортируйте файл медиа и продемонстрируйте переопределенные методы:- Создайте объект
Mediaс заголовком'Generic Content'и вызовитеplay() - Выведите пустую строку
- Создайте
Songс заголовком'Imagine'и исполнителем'John Lennon', затем вызовитеplay() - Выведите пустую строку
- Создайте
Videoс заголовком'Dart Tutorial'и длительностью360, затем вызовитеplay()
- Создайте объект
Аннотация @override документирует ваше намерение и помогает отлавливать ошибки. Если вы случайно напишете play() как plya(), аннотация предупредит вас о том, что такого метода в родительском классе не существует.
Ожидаемый вывод:
Playing: Generic Content
Playing song: Imagine by John Lennon
Playing: Dart Tutorial
Duration: 360 secondsШпаргалка
Аннотация @override помечает методы, которые намеренно заменяют метод родительского класса. Хотя она необязательна, она обеспечивает безопасность и ясность.
class Animal {
String name;
Animal(this.name);
void speak() {
print('$name makes a sound');
}
}
class Dog extends Animal {
Dog(String name) : super(name);
@override
void speak() {
print('$name barks: Woof!');
}
}Преимущества @override:
- Документирует намерение — показывает, что метод существует в родительском классе
- Отлавливает ошибки — анализатор Dart выдает предупреждение, если родительский метод не существует, предотвращая опечатки
Без @override опечатки создают новые методы вместо того, чтобы сигнализировать об ошибках:
class Cat extends Animal {
Cat(String name) : super(name);
void speek() { // Опечатка создает новый метод без предупреждения
print('$name meows');
}
}Вы можете вызвать версию родителя, используя super:
@override
void play() {
super.play(); // Сначала вызываем родительский метод
print('Additional behavior');
}Попробуйте сами
import 'media.dart';
void main() {
// TODO: Создайте объект Media с заголовком 'Generic Content' и вызовите play()
// TODO: Выведите пустую строку
// TODO: Создайте объект Song с заголовком 'Imagine' и исполнителем 'John Lennon', затем вызовите play()
// TODO: Выведите пустую строку
// TODO: Создайте объект Video с заголовком 'Dart Tutorial' и длительностью 360, затем вызовите play()
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыБиблиотеки и импортВведение в ООПКлассы и объектыКлючевое слово thisМетодыПеременные экземпляраОсновы конструкторовИтоги — Простой калькулятор4Null-безопасность
Введение в Null-безопасностьNullable и Non-Nullable типыОператоры ? и !Ключевое слово Late и Null-безопасностьNull-aware операторыNull-безопасность в классахИтоги — Система профилей пользователей7Абстрактные классы и интерфейсы
Абстрактные классыАбстрактные методыИнтерфейсы в DartНеявные интерфейсыРеализация против наследованияМножественные интерфейсыИтоги — Калькулятор фигур10Коллекции и обобщения
Обзор List, Set, MapТипобезопасные коллекцииОбобщенные классыОбобщенные методыОграничения обобщенийIterable и IteratorИтоги: Обобщенное хранилище13Продвинутые концепции ООП
Композиция против наследованияМетоды расширенияВызываемые классыЗапечатанные классы (Dart 3)Записи (Dart 3)Паттерны и сопоставление (3.0)Перечисления с методами16Проект: Управление библиотекой
Обзор проектаКлассы Book и User2Конструкторы в Dart
Конструктор по умолчаниюИменованные конструкторыСписки инициализацииКонстантные конструкторыФабричные конструкторыПеренаправляющие конструкторыИтоги — Shape Builder5Инкапсуляция
Публичные и приватные членыСоглашение о префиксе _Приватность на уровне библиотекГеттеры и сеттеры: подробный разборСкрытие данныхИтоги — Записи о студентах8Mixins
Введение в MixinsСоздание MixinsИспользование нескольких MixinsКлючевое слово on в MixinsMixin и наследованиеMixin и интерфейсИтоги: Система животных11Специальные методы
Переопределение toString()Переопределение hashCode и ==Интерфейс ComparableМетод call()Переопределение noSuchMethodПовторение — Пользовательская коллекция14Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy3Свойства классов
Члены экземпляра и статические членыПоля Final и ConstПеременные LateСтатические методы и поляГеттеры и сеттерыИтоги — Менеджер банковского счета6Наследование
Основы наследованияКлючевое слово superПереопределение методовАннотация @overrideКлючевое слово final для классовКонструкторы и наследованиеИтоги: Иерархия сотрудников9Полиморфизм
Основы полиморфизмаПолиморфизм через интерфейсыПроверка типов во время выполненияОператоры is и asКлючевое слово covariantИтоги — Обработчик платежей12Асинхронное ООП
Futures и async/awaitОсновы StreamsКонтроллеры StreamАсинхронные конструкторыАсинхронность в методах классовИтоги — Data Fetcher15Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн Репозиторий