Иногда нам приходится работать с сущностями, которые не имеют конкретного вопложени. Например, сущность "животное". Есть конкретные животные - кошка, собака и так далее, но животное как таковое не имеет конкретного воплощения. Или сущность "геометрическая фигура". Есть прямоугольник, квадрат, круг, треугольник, но сама по себе геометрическая фигура также не имеет конкретного воплощения. И обычно для описания подобных сущностей применяются абстрактные классы.
Абстрактные классы определяются с помощью ключевого слова abstract. Например, определим абстрактный класс геометрической фигуры:
abstract class Shape { }
Абстрактные классы похожи на обычные классы (также могут определять поля, методы, конструкторы) за тем исключением, что мы не можем создать напрямую объект абстрактного класса, используя его конструктор.
abstract class Shape { } void main (){ Shape shape = Shape();// ! Ошибка - так нельзя }
Как правило, абстрактные классы объявляют некоторый общий функционал, который по своему реализуют классы-наследники. Например, класс геометрической фигуры может иметь методы вычисления периметра, площади и т.д.
abstract class Shape { void calculateArea(){ print("Not Implemented"); } } class Rectangle extends Shape{ int width; int height; Rectangle(this.width, this.height); @override void calculateArea(){ int area = width * height; print("area = $area"); } } void main (){ Shape rect = Rectangle(20, 30); rect.calculateArea(); // area = 600 }
Здесь абстрактный класс геометрической фигуры определяет метод calculateArea()
, который выводит на консоль площадь фигуры. Класс
прямоугольника определяет свою реализацию для этого метода.
В примере выше метод calculateArea в базовом классе Shape не выполняет никакой полезной работы, так как у абстрактной фигуры не может быть площади. И в этом случае подобный метод лучше определить как абстрактный:
abstract class Shape { void calculateArea(); } class Rectangle extends Shape{ int width; int height; Rectangle(this.width, this.height); @override void calculateArea(){ int area = width * height; print("area = $area"); } } void main (){ Shape rect = Rectangle(20, 30); rect.calculateArea(); // area = 600 }
Абстрактный метод определяется также, как и обычный, только вместо тела метода после списка параметров идет точка с запятой: void calculateArea();
.
Важно отметить, что абстрактные методы могут быть определены только в абстрактных классах. Кроме того, если базовый класс определяет абстрактный метод, то класс-наследник обязательно должен его реализовать, то есть определить тело метода.