Menu
Coddy logo textTech

Переопределение методов

Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy — урок 38 из 110.

Переопределение методов происходит, когда дочерний класс предоставляет свою собственную реализацию метода, который уже существует в родительском классе. Это позволяет подклассам настраивать унаследованное поведение, сохраняя при этом ту же сигнатуру метода.

Когда вы определяете метод в дочернем классе с тем же именем и параметрами, что и в родительском, версия дочернего класса получает приоритет:

class Animal {
  String name;
  
  Animal(this.name);
  
  void speak() {
    print('$name makes a sound');
  }
}

class Dog extends Animal {
  Dog(String name) : super(name);
  
  void speak() {
    print('$name barks: Woof!');
  }
}

void main() {
  var animal = Animal('Generic');
  var dog = Dog('Buddy');
  
  animal.speak();  // Generic издает звук
  dog.speak();     // Buddy лает: Woof!
}

Когда вы вызываете speak() у экземпляра Dog, Dart выполняет версию Dog, а не версию Animal. Дочерний класс переопределил метод родительского класса.

Вы также можете комбинировать переопределение с super, чтобы расширить, а не заменить поведение родителя:

class Cat extends Animal {
  Cat(String name) : super(name);
  
  void speak() {
    super.speak();  // Сначала вызываем родительскую версию
    print('$name also purrs');
  }
}

Этот паттерн позволяет расширять существующую функциональность. Ключевое правило простое: одинаковое имя метода и параметры в дочернем классе заменяют реализацию родительского класса при вызове на экземплярах дочернего класса.

challenge icon

Задание

Легко

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

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

  • notification.dart: Определите здесь иерархию уведомлений:
    • Класс Notification (родительский) со свойствами String title и String message. Включите конструктор, принимающий оба значения, и метод send(), который выводит Notification: [title] - [message]
    • Класс EmailNotification, который расширяет Notification и добавляет свойство String recipient. Переопределите метод send(), чтобы он выводил Sending email to [recipient]: [title] - [message]
    • Класс PushNotification, который расширяет Notification и добавляет свойство String deviceId. Переопределите метод send(), чтобы он сначала вызывал родительский send() с помощью super, а затем выводил Pushed to device: [deviceId] на следующей строке
  • main.dart: Импортируйте файл уведомлений и продемонстрируйте переопределение методов в действии:
    • Создайте базовый объект Notification с заголовком 'Alert' и сообщением 'System update available'
    • Вызовите его метод send()
    • Выведите пустую строку
    • Создайте EmailNotification с заголовком 'Welcome', сообщением 'Thanks for signing up!' и получателем 'user@example.com'
    • Вызовите его метод send()
    • Выведите пустую строку
    • Создайте PushNotification с заголовком 'Reminder', сообщением 'Meeting in 10 minutes' и deviceId 'DEVICE-001'
    • Вызовите его метод send()

Обратите внимание, как EmailNotification полностью заменяет поведение родителя, в то время как PushNotification расширяет его, сначала вызывая super.send(). Оба подхода являются допустимыми способами переопределения методов в зависимости от ваших потребностей.

Ожидаемый вывод:

Notification: Alert - System update available

Sending email to user@example.com: Welcome - Thanks for signing up!

Notification: Reminder - Meeting in 10 minutes
Pushed to device: DEVICE-001

Шпаргалка

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

Чтобы переопределить метод, определите его в дочернем классе с тем же именем и параметрами:

class Animal {
  String name;
  
  Animal(this.name);
  
  void speak() {
    print('$name makes a sound');
  }
}

class Dog extends Animal {
  Dog(String name) : super(name);
  
  void speak() {
    print('$name barks: Woof!');
  }
}

void main() {
  var animal = Animal('Generic');
  var dog = Dog('Buddy');
  
  animal.speak();  // Generic makes a sound
  dog.speak();     // Buddy barks: Woof!
}

Вы можете использовать super, чтобы вызвать версию родителя и расширить, а не заменить поведение:

class Cat extends Animal {
  Cat(String name) : super(name);
  
  void speak() {
    super.speak();  // Сначала вызываем версию родителя
    print('$name also purrs');
  }
}

Попробуйте сами

import 'notification.dart';

void main() {
  // TODO: Создайте базовый Notification с заголовком 'Alert' и сообщением 'System update available'
  // Вызовите его метод send()

  // TODO: Выведите пустую строку

  // TODO: Создайте EmailNotification с:
  // - title: 'Welcome'
  // - message: 'Thanks for signing up!'
  // - recipient: 'user@example.com'
  // Вызовите его метод send()

  // TODO: Выведите пустую строку

  // TODO: Создайте PushNotification с:
  // - title: 'Reminder'
  // - message: 'Meeting in 10 minutes'
  // - deviceId: 'DEVICE-001'
  // Вызовите его метод send()
}
quiz iconПроверьте себя

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

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