4.08. Абстракция
Разработчику
Аналитику
Тестировщику
Архитектору
Инженеру
Абстракция
★ Абстракция – создание абстракных моделей объектов, которые скрывают внутреннюю реализацию. Позволяет работать с объектами, не вникая в их внутреннее устройство. Например, водитель использует педаль газа, не зная, как устроен двигатель.
Суть в том, чтобы скрыть сложные детали реализации и показать только важные свойства и функции объекта.
Зачем нужна абстракция?
- Упрощение сложных систем. Можно разбить сложные системы на понятные части. К примеру, мы в реальном мире не думаем о том, как работает двигатель автомобиля, чтобы управлять, нам хватит понимать, где педали, а где руль. В программировании можно так же спрятать внутрь реализацию.
- Сокрытие ненужных деталей. К примеру, другому программисту не нужно знать, как работает метод «мяукнуть()», ему достаточно лишь понимать, что он делает. Понятно, что мяукание издаст определённый звук. Но какие будут происходить процессы внутри «кота» - не нужно нам знать.
- Уменьшение сложности кода. Абстракция помогает структурировать код, делая его:
- читаемым (логика разбита на модули);
- поддерживаемым (изменения внутри класса не ломают внешний код);
- масштабируемым (можно добавлять новые функции, не переписывая всё).
- Унификация взаимодействия. Абстракция позволяет стандартизировать работу с объектами. Допустим, в игре разные персонажи могут иметь метод attack(), но реализация у мечника и мага будет отличаться.
Абстракция достигается за счёт:
- абстрактных классов;
- абстрактных методов;
- сокрытия данных.

★ Абстрактный класс – это класс, который нельзя создать напрямую – только через наследование. Содержит абстрактные методы и/или обычные методы.
Абстрактный класс нужен для того, чтобы задать общую структуру для дочерних классов и запретить создание объектов «неполного» типа.
Нельзя создавать экземпляр абстрактного класса, но если сделать неабстрактного наследника, то можно уже создавать объекты.
Пример на Java:
// Абстрактный класс "Транспорт"
abstract class Transport {
private String name; // поле
public Transport(String name) { // конструктор
this.name = name;
}
// Абстрактный метод (без тела)
public abstract void move();
// Обычный метод
public void honk() {
System.out.println(name + " сигналит: Би-бип!");
}
}
// Класс-наследник "Машина"
class Car extends Transport {
public Car(String name) {
super(name); // вызываем конструктор родителя
}
// Реализация абстрактного метода
@Override
public void move() {
System.out.println(getClass().getSimpleName() + " едет по дороге!");
}
}
// Класс-наследник "Самолет"
class Airplane extends Transport {
public Airplane(String name) {
super(name);
}
@Override
public void move() {
System.out.println(getClass().getSimpleName() + " летит в небе!");
}
}
public class Main {
public static void main(String[] args) {
Transport car = new Car("Toyota");
Transport airplane = new Airplane("Boeing 747");
car.move(); // Вывод: "Car едет по дороге!"
car.honk(); // Вывод: "Toyota сигналит: Би-бип!"
airplane.move(); // Вывод: "Airplane летит в небе!"
airplane.honk(); // Вывод: "Boeing 747 сигналит: Би-бип!"
}
}
Transport – абстрактный класс с:
- абстрактным методом move();
- обычным методом honk().
Car и Airplane – наследники, которые обязаны реализовать move().
И нельзя создать Transport напрямую:
Transport t = new Transport(); // Ошибка! Transport абстрактный.
★ Абстрактный метод – это метод без реализации, который обязаны переопределить все дочерние классы. Принцип тот же – это просто указание, что абстрактный класс содержит этот метод, но как работает метод – не указано. Так, программист реализует критичную логику, и использует унифицированный интерфейс для разных классов. Словом, будет порядок. Пример:
abstract class Animal {
abstract void makeSound(); // абстрактный метод
}
class Dog extends Animal {
void makeSound() { // обязательная реализация
System.out.println("Гав!");
}
}
★ Интерфейсы – полностью абстрактный «контракт», где все методы абстрактные. В отличие от абстрактного класса, в интерфейсе нет полей и реализованных методов, и класс может реализовать много интерфейсов, но наследовать только один абстрактный класс. Пример:
interface Flyable {
void fly(); // абстрактный метод
}
class Bird implements Flyable {
public void fly() {
System.out.println("Лечу как птица!");
}
}
Ещё один пример интерфейса:
// Интерфейс "Ремонтируемый"
interface Repairable {
void repair();
}
// Абстрактный класс + интерфейс
abstract class Transport implements Repairable {
public abstract void move();
// Общий метод для всех наследников
public void startEngine() {
System.out.println("Двигатель запущен.");
}
}
class Bicycle extends Transport {
@Override
public void move() {
System.out.println("Велосипед едет!");
}
@Override
public void repair() {
System.out.println("Чиним цепь...");
}
}
public class Main {
public static void main(String[] args) {
Bicycle bike = new Bicycle();
bike.startEngine(); // Вывод: "Двигатель запущен." (наследовано)
bike.move(); // Вывод: "Велосипед едет!"
bike.repair(); // Вывод: "Чиним цепь..."
}
}
Интерфейс – только контракт (все методы абстрактные).
Абстрактный класс – частичная реализация + контракт.
Абстрактные классы особенно полезны в библиотеках и фреймворках, когда надо спрятать внутри всю логику и дать пользователю инструмент.
Таким образом,
- «Что» – это публичный интерфейс (какие методы доступны пользователю);
- «Как» - скрытая реализация (как эти методы работают внутри).
Где применяется абстракция – примеры:
- Библиотеки и фреймворки, к примеру, в ORM вы работаете с моделями вроде Model.save(), не зная самих SQL-запросов.
- Игры – абстрактный класс Enemy (враг) с методом attack(), где Dragon и Zombie реализуют свою логику атаки.
- GUI – кнопка Button.click() скрывает детали отрисовки и обработки событий.
- API – например, оплата идёт путем вызова метода, без знания протоколов.