Ответ
В Dart абстрактный класс — это класс, который нельзя инстанциировать напрямую с помощью конструктора. Он служит шаблоном или контрактом для своих подклассов, определяя общий интерфейс (методы, свойства) и, возможно, часть реализации.
Ключевые характеристики:
- Объявляется с ключевым словом
abstract. - Может содержать абстрактные методы (объявлены без тела, с
;). - Может содержать конкретные методы (с полной реализацией).
- Может содержать поля, геттеры, сеттеры и конструкторы (хотя конструктор абстрактного класса можно вызвать только из конструктора подкласса).
- Класс, наследующий абстрактный класс, должен реализовать (override) все его абстрактные методы, если сам не объявлен абстрактным.
Пример: Моделирование геометрических фигур
abstract class Shape {
// Абстрактный метод: должен быть реализован в подклассе
double area();
// Абстрактный геттер
String get name;
// Конкретный метод с реализацией, доступный всем подклассам
void printDescription() {
print('I am a $name with area: ${area().toStringAsFixed(2)}');
}
}
class Circle extends Shape {
final double radius;
Circle(this.radius);
@override
double area() => 3.14159 * radius * radius;
@override
String get name => 'Circle';
}
class Rectangle extends Shape {
final double width;
final double height;
Rectangle(this.width, this.height);
@override
double area() => width * height;
@override
String get name => 'Rectangle';
}
void main() {
final shapes = <Shape>[
Circle(5),
Rectangle(4, 6),
];
for (final shape in shapes) {
shape.printDescription(); // Полиморфный вызов
// Вывод:
// I am a Circle with area: 78.54
// I am a Rectangle with area: 24.00
}
}
Сравнение с интерфейсами (implicit interfaces) в Dart: В Dart каждый класс неявно определяет интерфейс. Абстрактный класс, не содержащий конкретных методов, концептуально похож на интерфейс. Однако ключевое отличие в том, что абстрактный класс может содержать реализацию и состояние (поля), а также ограничивать иерархию наследования (класс может наследовать только один абстрактный класс, но реализовать много интерфейсов). Я использую абстрактные классы, когда хочу задать общее поведение и частичную реализацию для группы связанных классов.
Ответ 18+ 🔞
Э, сабака сука, ну слушай сюда, разберёмся с этими абстрактными классами в Dart. Представь себе, что это как чертёж от инженера, который сам по себе — просто бумажка, ёпта. Ты не можешь построить дом из чертежа, но все строители, которые по нему работают, обязаны сделать окна, двери и крышу именно так, как там нарисовано. Вот и абстрактный класс — это такой чертёж для других классов.
Что это за зверь такой:
- Объявляешь его с волшебным словом
abstract. Без него — ни хуя себе, не сработает. - Может содержать абстрактные методы — это когда метод объявлен, но у него вместо тела точка с запятой. Как будто крикнул подмастерьям: "Сделайте хуйню!", но как именно — не сказал. Пусть сами думают.
- Но может и конкретные методы иметь — уже с готовой реализацией, чтобы подклассы не парились и могли пользоваться.
- Поля, геттеры, сеттеры, конструкторы — всё может быть. Но конструктор этого абстрактного чудака можно вызвать только из конструктора класса-наследника, иначе доверия ебать ноль.
Короче, пример на пальцах: Геометрические фигуры
Представь, ты начальник цеха по производству фигур. Ты говоришь: "Все фигуры должны уметь считать свою площадь и иметь имя. А как именно считать — это ваши проблемы, мартышлюшки".
abstract class Shape {
// Абстрактный метод: объявил и послал всех на хуй. Пусть наследники реализуют.
double area();
// Абстрактный геттер. Без имени — никуда.
String get name;
// А вот это уже конкретный метод. Готовый инструмент. Наследники могут просто пользоваться.
void printDescription() {
print('Я $name, и моя площадь: ${area().toStringAsFixed(2)}');
}
}
// Приходит первый работяга — Круг.
class Circle extends Shape {
final double radius;
Circle(this.radius);
@override // Говорим: "Батя, я сделал по-своему, но как ты велел!"
double area() => 3.14159 * radius * radius; // Формулу, блядь, ещё в школе учил.
@override
String get name => 'Круг';
}
// Второй работяга — Прямоугольник.
class Rectangle extends Shape {
final double width;
final double height;
Rectangle(this.width, this.height);
@override
double area() => width * height; // Ширина на высоту, ебать копать, что может быть проще?
@override
String get name => 'Прямоугольник';
}
void main() {
// Создаём коллекцию фигур. Главное, что они все — Shape. Нам похуй на конкретный тип.
final shapes = <Shape>[
Circle(5),
Rectangle(4, 6),
];
for (final shape in shapes) {
shape.printDescription(); // Магия полиморфизма! Вызовется своя реализация area() для каждого.
// Вывод:
// Я Круг, и моя площадь: 78.54
// Я Прямоугольник, и моя площадь: 24.00
}
}
А в чём отличие от интерфейсов, спросишь ты? В Dart каждый класс неявно определяет интерфейс, это да. Если абстрактный класс состоит только из абстрактных методов, то он, в общем-то, и есть интерфейс. Но фишка в том, что абстрактный класс может быть хитрой жопой: он может уже часть работы сделать за тебя (конкретные методы) и хранить какое-то состояние (поля). И ещё: наследоваться можно только от одного такого класса-родителя, а интерфейсов реализовать — овердохуища.
Итог: Использую абстрактный класс, когда у меня есть группа очень похожих сущностей, у которых общая не только "форма" (методы), но и какая-то базовая "начинка" (реализация). Когда хочу сказать: "Вот вам основа, дебилы, остальное доделывайте сами, но строго по моим правилам".
Видео-ответы
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶
▶