Реализация против наследования
Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy. Урок 47 из 110.
Теперь, когда вы понимаете и extends, и implements, давайте уточним, когда использовать каждый из них.
Используйте extends, когда хотите унаследовать behavior. Ваш подкласс получает весь код родительского класса бесплатно и может развивать его:
class Animal {
void breathe() {
print('Breathing...');
}
}
class Dog extends Animal {
void bark() {
print('Woof!');
}
}
void main() {
var dog = Dog();
dog.breathe(); // Унаследовано — работает автоматически
dog.bark();
}Используйте implements, когда хотите гарантировать структуру без наследования кода. Вы должны написать каждый метод самостоятельно:
class Robot implements Animal {
@override
void breathe() {
print('Ventilating circuits...'); // Полностью кастомная реализация
}
}Ключевое различие: extends означает «я являюсь типом этого», тогда как implements означает «я умею делать то же, что и это». Dog — это Animal, и он дышит так же. Robot — не животное, но он может выполнять тот же контракт, используя собственную логику.
Помни: ты можешь расширить только один класс, но можешь реализовать множество интерфейсов. Выбирай extends для настоящих отношений наследования, а implements — когда тебе нужна гибкость или ты хочешь обеспечить соблюдение контракта без совместного использования деталей реализации.
Задание
ЛегкоДавайте создадим систему работников, которая демонстрирует, когда использовать extends, а когда — implements. Вы создадите базовый класс работника, а затем покажете оба подхода: один класс действительно «является» работником и наследует поведение, а другой просто «может делать» то, что делает работник, но использует полностью custom логику.
Вы организуете код в двух файлах:
worker.dart: Определите здесь иерархию работников:- Класс
Workerсо свойствомString nameи конструктором. Включите методwork(), который выводит[name] is working..., и методtakeBreak(), который выводит[name] takes a coffee break - Класс
OfficeWorker, который extendsWorker. Добавьте свойствоString department. Переопределитеwork(), чтобы он выводил[name] is typing reports in [department], но сохраните inherited поведениеtakeBreak() - Класс
RobotWorker, который implementsWorker. Добавьте свойствоString model. Поскольку роботы на самом деле не являются работниками, но могут делать то, что делают работники, предоставьте Completely custom реализации:work()должен выводитьRobot [model] is assembling parts, аtakeBreak()должен выводитьRobot [model] is recharging
- Класс
main.dart: Импортируйте файл работника и продемонстрируйте оба подхода:- Создайте
OfficeWorkerс именем'Alice'в отделе'Marketing' - Создайте
RobotWorkerс моделью'RX-7' - Для офисного работника вызовите
work(), затемtakeBreak() - Выведите пустую строку
- Для робота-работника вызовите
work(), затемtakeBreak()
- Создайте
Обратите внимание, как OfficeWorker автоматически наследует takeBreak(), потому что он extends Worker — он действительно «является» работником. В то же время RobotWorker must предоставить собственную реализацию для всего, потому что он только implements интерфейс — он «может делать» то, что делает работник, но по-своему, по-роботизированному.
Ожидаемый вывод:
Alice is typing reports in Marketing
Alice takes a coffee break
Robot RX-7 is assembling parts
Robot RX-7 is rechargingПопробуйте сами
import 'worker.dart';
void main() {
// TODO: Создайте OfficeWorker по имени 'Alice' в отделе 'Marketing'
// TODO: Создайте RobotWorker с моделью 'RX-7'
// TODO: Для офисного работника вызовите work(), затем takeBreak()
// TODO: Выведите пустую строку
// TODO: Для робота-работника вызовите work(), затем takeBreak()
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
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
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн РепозиторийПотренируйтесь самостоятельно: Онлайн-компилятор Dart