Ответ
extends — это ключевое слово в Dart, используемое для создания подкласса (наследника) от другого класса (суперкласса или родителя). Наследник получает все публичные и защищенные (protected через конвенцию _) поля и методы родителя, может их переопределять и добавлять новые.
Основные принципы:
- Одиночное наследование: Класс может наследовать только от одного суперкласса.
- Переопределение методов: Используется аннотация
@override. - Конструкторы: Конструктор родителя вызывается с помощью
super()в теле конструктора наследника.
Практический пример из Flutter: Создание кастомного виджета с дополнительной логикой.
// Базовый класс для всех экранов в приложении
abstract class BaseScreen extends StatelessWidget {
final String screenTitle;
const BaseScreen({required this.screenTitle, Key? key}) : super(key: key);
// Общий метод для всех экранов
AppBar buildAppBar(BuildContext context) {
return AppBar(
title: Text(screenTitle),
centerTitle: true,
);
}
// Абстрактный метод, который должны реализовать наследники
Widget buildBody(BuildContext context);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: buildAppBar(context),
body: buildBody(context),
);
}
}
// Конкретный экран, наследующий общую структуру
class HomeScreen extends BaseScreen {
const HomeScreen({Key? key}) : super(screenTitle: 'Главная', key: key);
@override
Widget buildBody(BuildContext context) {
return Center(
child: ElevatedButton(
onPressed: () {},
child: Text('Действие'),
),
);
}
// Можно переопределить и метод родителя
@override
AppBar buildAppBar(BuildContext context) {
final defaultAppBar = super.buildAppBar(context);
return AppBar(
title: defaultAppBar.title,
actions: [IconButton(onPressed: () {}, icon: Icon(Icons.settings))],
);
}
}
Итог: extends — фундаментальный механизм для повторного использования кода и построения иерархий в объектно-ориентированном Dart.
Ответ 18+ 🔞
Давай разберем эту тему, чтобы в голове всё встало на свои места, а не болталось как хуй с горы.
extends — это, по сути, твой пропуск в мир наследования в Dart. Грубо говоря, ты берешь один класс и делаешь на его основе другой, который получает всё его добро: поля, методы, всё такое. Но есть нюансы, ёпта.
Что происходит, когда ты пишешь extends?
Твой новый класс (наследник, он же подкласс) становится полноправным обладателем всего, что было публичным или условно-защищенным (это те поля с подчеркиванием _, которые по факту видны в том же файле) у родителя. Можешь этим пользоваться, можешь это переписывать (override), а можешь и своё свежее прикрутить.
Главные правила, которые надо запомнить:
- Один родитель, и всё. В Dart нельзя наследоваться от десяти классов сразу, только одиночное наследование. Не как у некоторых, во все дыры давалка.
- Переопределение — это святое. Хочешь поменять работу метода родителя? Пожалуйста, но ставь аннотацию
@override, чтобы все (и особенно компилятор) поняли, что ты делаешь это осознанно, а не просто так, распиздяй. - Конструкторы. Родительский конструктор сам по себе не вызовется. Тебе надо явно позвать его через
super()в теле конструктора наследника. Иначе — пиши пропало.
Зачем это всё, спросишь? Ну, ёбать копать, чтобы не копипастить один и тот же код в каждом втором классе. Создал один базовый класс с общей логикой — и потом от него только пляшешь.
Смотри, как это в Flutter'е выглядит на живом примере. Допустим, у нас в приложении куча экранов, и у каждого должен быть AppBar с заголовком. Чтобы не писать этот Scaffold раз по тридцать, сделаем базовый класс.
// Базовый класс для всех экранов. Делаем его абстрактным, чтобы с него нельзя было создать объект.
abstract class BaseScreen extends StatelessWidget {
final String screenTitle;
const BaseScreen({required this.screenTitle, Key? key}) : super(key: key);
// Общий метод для построения шапки. Наследники могут его использовать или переписать.
AppBar buildAppBar(BuildContext context) {
return AppBar(
title: Text(screenTitle),
centerTitle: true,
);
}
// А вот это — абстрактный метод. Он как долговая расписка.
// Каждый наследник ОБЯЗАН будет сказать: "Вот, брат, держи, я тело экрана реализовал".
Widget buildBody(BuildContext context);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: buildAppBar(context), // Используем общий метод
body: buildBody(context), // А тут ждем реализацию от наследника
);
}
}
// А вот наш конкретный экран. Он наследуется от BaseScreen.
class HomeScreen extends BaseScreen {
const HomeScreen({Key? key}) : super(screenTitle: 'Главная', key: key);
// Выполняем долговое обязательство — реализуем buildBody.
@override
Widget buildBody(BuildContext context) {
return Center(
child: ElevatedButton(
onPressed: () {},
child: Text('Нажми меня'),
),
);
}
// А тут мы ещё и шапку родительскую решили улучшить.
// Сначала вызываем метод родителя (super.buildAppBar), чтобы получить стандартную шапку,
// а потом к ней ещё кнопку настроек прикручиваем.
@override
AppBar buildAppBar(BuildContext context) {
final defaultAppBar = super.buildAppBar(context);
return AppBar(
title: defaultAppBar.title,
actions: [IconButton(onPressed: () {}, icon: Icon(Icons.settings))],
);
}
}
Итог, чувак: extends — это краеугольный камень ООП в Dart. Не освоишь его — будешь потом везде копипастить код, а потом один фикс вносить в овердохуища мест, и сам от себя охуеешь. Используй грамотно, строй иерархии, и код станет чище и суше.