Абстрактные методы
Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy — урок 44 из 110.
Абстрактный метод — это метод, объявленный внутри абстрактного класса, который не имеет тела. Он определяет сигнатуру метода, но оставляет реализацию каждому подклассу. Любой класс, который расширяет абстрактный класс, должен переопределить все абстрактные методы, иначе он также будет абстрактным.
abstract class Animal {
// Абстрактный метод — без тела, должен быть реализован подклассами
String makeSound();
// Конкретный метод — имеет тело, общий для всех подклассов
void breathe() {
print('Breathing...');
}
}
class Dog extends Animal {
@override
String makeSound() {
return 'Woof!'; // Необходимо предоставить реализацию
}
}
class Cat extends Animal {
@override
String makeSound() {
return 'Meow!'; // Другая реализация, та же сигнатура
}
}Если подкласс забывает реализовать абстрактный метод, Dart выдаст ошибку компиляции. В этом и заключается весь смысл — абстрактные методы обеспечивают соблюдение контракта. Гарантируется, что каждый подкласс будет иметь этот метод, поэтому вы можете безопасно вызывать его у любого экземпляра абстрактного типа.
// Вы можете использовать абстрактный тип в качестве типа переменной
Animal a = Dog();
print(a.makeSound()); // Гав!
Animal b = Cat();
print(b.makeSound()); // Мяу!Абстрактные методы отличаются от конкретных методов в абстрактном классе. Конкретные методы имеют тело и наследуются как есть. Абстрактные методы не имеют тела и должны быть переопределены.
Вы можете сочетать и то, и другое в одном и том же абстрактном классе, чтобы совместно использовать определенное поведение, заставляя при этом подклассы определять свое собственное поведение для остальных случаев.
| Особенность | Абстрактный метод | Конкретный метод |
|---|---|---|
| Наличие тела | Нет | Да |
| Обязательное переопределение | Да | Нет |
| Цель | Обеспечение контракта | Общее поведение |
| Где используется | Только в абстрактном классе | В любом классе |
Задание
ЛегкоДавайте создадим калькулятор фигур, который демонстрирует работу абстрактных методов. Вы определите абстрактный класс с абстрактными методами, которые каждая фигура должна реализовать по-своему, а затем будете использовать эти фигуры через общий интерфейс.
Вы организуете свой код в четырех файлах:
shape.dart: Определите абстрактный классShapeс полемfinalcolor(String) и конструктором, который его инициализирует. Объявите два абстрактных метода:double area()иdouble perimeter(). Также добавьте конкретный методdescribe(), который выводитA [color] shape with area: [area] and perimeter: [perimeter]. Посколькуarea()иperimeter()являются абстрактными, каждый подкласс предоставит свой собственный расчет, ноdescribe()будет работать для всех них без переопределения.circle.dart: Создайте классCircle, который расширяетShape. У него есть полеfinalradius(double). Его конструктор принимаетcolorиradiusи передаетcolorвsuper. Реализуйтеarea(), чтобы он возвращал3.14 * radius * radius, иperimeter(), чтобы он возвращал2 * 3.14 * radius.rectangle.dart: Создайте классRectangle, который расширяетShape. У него есть поляfinalwidthиheight(оба double). Его конструктор принимаетcolor,widthиheightи передаетcolorвsuper. Реализуйтеarea(), чтобы он возвращалwidth * height, иperimeter(), чтобы он возвращал2 * (width + height).main.dart: Импортируйте все файлы. СоздайтеCircleс цветом'red'и радиусом5.0, иRectangleс цветом'blue', шириной4.0и высотой6.0. Вызовитеdescribe()для каждой фигуры. Затем создайтеList<Shape>, содержащий обе фигуры, переберите список в цикле и выведитеArea: [area]для каждой фигуры.
Ожидаемый вывод:
A red shape with area: 78.5 and perimeter: 31.400000000000002
A blue shape with area: 24.0 and perimeter: 20.0
Area: 78.5
Area: 24.0Шпаргалка
Абстрактный метод — это метод, объявленный в абстрактном классе без тела. Подклассы должны переопределить его, чтобы предоставить свою собственную реализацию.
abstract class Animal {
// Абстрактный метод — без тела
String makeSound();
// Конкретный метод — имеет тело
void breathe() {
print('Breathing...');
}
}Подклассы должны реализовать все абстрактные методы:
class Dog extends Animal {
@override
String makeSound() {
return 'Woof!';
}
}
class Cat extends Animal {
@override
String makeSound() {
return 'Meow!';
}
}Вы можете использовать абстрактный тип в качестве типа переменной:
Animal a = Dog();
print(a.makeSound()); // Woof!
Animal b = Cat();
print(b.makeSound()); // Meow!| Особенность | Абстрактный метод | Конкретный метод |
|---|---|---|
| Имеет тело | Нет | Да |
| Обязательно переопределить | Да | Нет |
| Цель | Обеспечение контракта | Общий доступ к поведению |
| Где | Только в абстрактном классе | В любом классе |
Попробуйте сами
import 'shape.dart';
import 'circle.dart';
import 'rectangle.dart';
void main() {
// TODO: Создайте Circle с цветом 'red' и радиусом 5.0
// TODO: Создайте Rectangle с цветом 'blue', шириной 4.0 и высотой 6.0
// TODO: Вызовите describe() для circle
// TODO: Вызовите describe() для rectangle
// TODO: Создайте List<Shape>, содержащий обе фигуры
// TODO: Пройдите циклом по списку и выведите "Area: [area]" для каждой фигуры
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
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
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн Репозиторий