Инкапсуляция
Скрываем поля, даём доступ только через методы.
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 class | interface |
|---|---|---|
| Наследование | Только одно (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) |