Menu
Coddy logo textTech

Абстрактные методы

Часть раздела Объектно-ориентированное программирование путешествия по 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());  // Мяу!

Абстрактные методы отличаются от конкретных методов в абстрактном классе. Конкретные методы имеют тело и наследуются как есть. Абстрактные методы не имеют тела и должны быть переопределены.

Вы можете сочетать и то, и другое в одном и том же абстрактном классе, чтобы совместно использовать определенное поведение, заставляя при этом подклассы определять свое собственное поведение для остальных случаев.

ОсобенностьАбстрактный методКонкретный метод
Наличие телаНетДа
Обязательное переопределениеДаНет
ЦельОбеспечение контрактаОбщее поведение
Где используетсяТолько в абстрактном классеВ любом классе
challenge icon

Задание

Легко

Давайте создадим калькулятор фигур, который демонстрирует работу абстрактных методов. Вы определите абстрактный класс с абстрактными методами, которые каждая фигура должна реализовать по-своему, а затем будете использовать эти фигуры через общий интерфейс.

Вы организуете свой код в четырех файлах:

  • shape.dart: Определите абстрактный класс Shape с полем final color (String) и конструктором, который его инициализирует. Объявите два абстрактных метода: double area() и double perimeter(). Также добавьте конкретный метод describe(), который выводит A [color] shape with area: [area] and perimeter: [perimeter]. Поскольку area() и perimeter() являются абстрактными, каждый подкласс предоставит свой собственный расчет, но describe() будет работать для всех них без переопределения.
  • circle.dart: Создайте класс Circle, который расширяет Shape. У него есть поле final radius (double). Его конструктор принимает color и radius и передает color в super. Реализуйте area(), чтобы он возвращал 3.14 * radius * radius, и perimeter(), чтобы он возвращал 2 * 3.14 * radius.
  • rectangle.dart: Создайте класс Rectangle, который расширяет Shape. У него есть поля final width и 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]" для каждой фигуры
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование