RU | EN | DE

Инкапсуляция

Скрываем поля, даём доступ только через методы.

class BankAccount {
    private double balance;
    public void deposit(double amount) { balance += amount; }
    public void withdraw(double amount) {
        if (amount <= balance) balance -= amount;
        else throw new IllegalArgumentException("Недостаточно средств");
    }
    public double getBalance() { return balance; }
}
 
class Main {
    public static void main(String[] args) {
        BankAccount acc = new BankAccount();
        acc.deposit(100);
        acc.withdraw(40);
        System.out.println(acc.getBalance()); // 60.0
    }
}

Наследование

class Animal {
    void sound() { System.out.println("Some sound"); }
}
 
class Dog extends Animal {
    @Override
    void sound() { System.out.println("Woof!"); }
}
 
class Main {
    public static void main(String[] args) {
        Animal a = new Dog();
        a.sound(); // Woof!
    }
}

Абстракция

abstract class Shape {
    abstract double area();
}
 
class Circle extends Shape {
    double r;
    Circle(double r) { this.r = r; }
    @Override double area() { return Math.PI * r * r; }
}
 
class Main {
    public static void main(String[] args) {
        Shape s = new Circle(3);
        System.out.println(s.area()); // 28.27
    }
}

Полиморфизм

interface Payment {
    void pay(double amount);
}
 
class CardPayment implements Payment {
    public void pay(double amount) {
        System.out.println("Pay by card: " + amount);
    }
}
 
class CashPayment implements Payment {
    public void pay(double amount) {
        System.out.println("Pay by cash: " + amount);
    }
}
 
class Main {
    public static void main(String[] args) {
        Payment p = new CardPayment();
        p.pay(100); // Pay by card: 100
    }
}

Разница между abstract class и interface

📘 Определения

abstract class — это класс, который нельзя создать напрямую (через new), но он может содержать как реализованные методы, так и абстрактные (без тела). Используется для общей логики и состояния, которые должны наследовать дочерние классы.

interface — это контракт (набор методов), который гарантирует поведение, но не содержит состояния (до Java 8).

Современные интерфейсы (с Java 8+) могут содержать:

  • default методы (с реализацией),
  • static методы,
  • private методы (с Java 9).

📗 Ключевые различия

Критерийabstract classinterface
НаследованиеТолько одно (Java поддерживает single inheritance)Можно реализовать несколько интерфейсов
Состояние (поля)Можно иметь обычные поля (в т. ч. protected/private)Только public static final (константы)
МетодыМожет содержать реализованные и абстрактные методыДо Java 8 — только абстрактные; после — также default и static
КонструкторМожет иметь конструктор (для наследников)Не может иметь конструктор
Когда использоватьКогда нужно общее состояние и частичная реализацияКогда нужно задать поведение (контракт) для разных классов
Пример примененияБазовый класс Animal, от которого наследуются Dog, CatИнтерфейс Comparable<T> или Serializable

📙 Пример кода

// Абстрактный класс — имеет общее состояние
public abstract class Animal {
    protected String name;
    public Animal(String name) {
        this.name = name;
    }
 
    public abstract void makeSound();
 
    public void sleep() {
        System.out.println(name + " is sleeping...");
    }
}
 
// Интерфейс — задаёт поведение
public interface Flyable {
    void fly();
}
 
// Класс, наследующий абстрактный и реализующий интерфейс
public class Bird extends Animal implements Flyable {
    public Bird(String name) {
        super(name);
    }
 
    @Override
    public void makeSound() {
        System.out.println(name + " chirps");
    }
 
    @Override
    public void fly() {
        System.out.println(name + " flies away!");
    }
}

💡 Вывод:

  • Абстрактный класс описывает что объект есть.
  • Интерфейс описывает что объект умеет делать.

Принципы SOLID

SOLID — это набор из 5 принципов проектирования, которые помогают создавать гибкий, читаемый и поддерживаемый код.
Используются в ООП и архитектуре приложений, особенно в Spring, DDD, чистой архитектуре.

S — Single Responsibility Principle (Принцип единственной ответственности)

Суть:
Класс должен иметь только одну причину для изменения, то есть заниматься только одной задачей.

Плохо:

class UserService {
    void registerUser(User user) { ... }      // регистрация
    void sendEmail(User user) { ... }         // и сразу логика отправки почты
}

Хорошо:

class UserService {
    void registerUser(User user) { ... }
}
 
class EmailService {
    void sendEmail(User user) { ... }
}

📍 Применяется в Spring: Controller, Service, Repository — каждый отвечает за свой слой.

O — Open/Closed Principle (Принцип открытости/закрытости)

Суть:
Классы должны быть открыты для расширения, но закрыты для изменения.
→ Лучше добавлять новые классы, чем менять старые.

Пример:

interface Payment {
    void pay();
}
 
class CardPayment implements Payment { ... }
class PaypalPayment implements Payment { ... }
class ApplePay implements Payment { ... }
 
// Класс использует интерфейс, не конкретную реализацию
class PaymentProcessor {
    void process(Payment payment) {
        payment.pay();
    }
}

📍 Применяется при внедрении зависимостей (Dependency Injection).

L — Liskov Substitution Principle (Принцип подстановки Барбары Лисков)

Суть:
Объекты подклассов должны замещать объекты родительских классов без изменения поведения программы.

Неправильно:

class Bird { void fly() { ... } }
 
class Penguin extends Bird {
    void fly() { throw new UnsupportedOperationException(); }
}

Пингвин — птица, но не летает → нарушает принцип.

Решение:
Выделить интерфейс Flyable и использовать композицию, а не наследование.

I — Interface Segregation Principle (Принцип разделения интерфейсов)

Суть:
Клиенты не должны зависеть от методов, которые они не используют.
Лучше много мелких интерфейсов, чем один огромный.

Плохо:

interface Worker {
    void work();
    void eat();
}
class Robot implements Worker {
    public void work() {}
    public void eat() {} // не умеет есть
}

Хорошо:

interface Workable { void work(); }
interface Eatable { void eat(); }
class Robot implements Workable { public void work() {} }
class Human implements Workable, Eatable { ... }

📍 Применяется при проектировании API и микросервисов.

D — Dependency Inversion Principle (Принцип инверсии зависимостей)

Суть:
Модули верхнего уровня не должны зависеть от модулей нижнего уровня — оба должны зависеть от абстракций.

Плохо:

class MySQLDatabase { void connect() { ... } }
 
class UserRepository {
    private MySQLDatabase db = new MySQLDatabase(); // жёсткая зависимость
}

Хорошо (через интерфейс):

interface Database { void connect(); }
 
class MySQLDatabase implements Database { ... }
class PostgreSQLDatabase implements Database { ... }
 
class UserRepository {
    private final Database db;
    public UserRepository(Database db) { this.db = db; }
}

📍 В Spring это реализуется через Dependency Injection (@Autowired, @Service, @Repository).

🧩 Применение SOLID в реальной Java-архитектуре

ПринципГде встречается в Spring/Java
SРазделение слоёв: Controller / Service / Repository
OРасширяемые интерфейсы, стратегии (Strategy Pattern)
LКорректная иерархия DTO и Entity
IМелкие интерфейсы: CrudRepository, JpaRepository
DВнедрение зависимостей (Spring IoC Container)