← Назад к вопросам

Что такое паттерны программирования?

1.0 Junior🔥 191 комментариев
#SOLID и паттерны проектирования

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Паттерны программирования (Design Patterns)

Определение

Паттерн программирования (Design Pattern) — это проверенное решение часто встречаемой проблемы в коде. Паттерны описывают структуру, поведение и отношения между элементами кода для решения типичных задач.

Паттерны — это как рецепты или шаблоны, которые помогают:

  • Избежать ошибок при проектировании
  • Сделать код более гибким и переиспользуемым
  • Улучшить коммуникацию в команде (общий язык)

Категории паттернов

1. Порождающие паттерны (Creational)

Решают задачи создания объектов.

Singleton (Одиночка)

Гарантирует, что класс имеет только один экземпляр, и предоставляет глобальный доступ.

public class DatabaseConnection {
    private static DatabaseConnection instance;
    
    private DatabaseConnection() {}
    
    public static synchronized DatabaseConnection getInstance() {
        if (instance == null) {
            instance = new DatabaseConnection();
        }
        return instance;
    }
}

// Использование
DatabaseConnection db = DatabaseConnection.getInstance();
DatabaseConnection db2 = DatabaseConnection.getInstance();
assert db == db2;  // true - один объект

Factory (Фабрика)

Создаёт объекты без указания точных классов.

public abstract class DatabaseFactory {
    public static Database createDatabase(String type) {
        switch (type) {
            case "postgresql":
                return new PostgresqlDatabase();
            case "mysql":
                return new MysqlDatabase();
            default:
                throw new IllegalArgumentException("Unknown type: " + type);
        }
    }
}

public interface Database {
    void connect();
}

public class PostgresqlDatabase implements Database {
    @Override
    public void connect() {
        System.out.println("Connected to PostgreSQL");
    }
}

// Использование
Database db = DatabaseFactory.createDatabase("postgresql");
db.connect();

Builder (Строитель)

Строит сложные объекты пошагово.

public class User {
    private String name;
    private String email;
    private int age;
    private String phone;
    
    public static class UserBuilder {
        private String name;
        private String email;
        private int age;
        private String phone;
        
        public UserBuilder name(String name) {
            this.name = name;
            return this;
        }
        
        public UserBuilder email(String email) {
            this.email = email;
            return this;
        }
        
        public UserBuilder age(int age) {
            this.age = age;
            return this;
        }
        
        public UserBuilder phone(String phone) {
            this.phone = phone;
            return this;
        }
        
        public User build() {
            User user = new User();
            user.name = this.name;
            user.email = this.email;
            user.age = this.age;
            user.phone = this.phone;
            return user;
        }
    }
}

// Использование
User user = new User.UserBuilder()
    .name("John")
    .email("john@example.com")
    .age(30)
    .build();

Prototype (Прототип)

Создаёт объект путём копирования существующего объекта.

public class Document implements Cloneable {
    private String title;
    private String content;
    
    @Override
    public Document clone() throws CloneNotSupportedException {
        return (Document) super.clone();
    }
}

// Использование
Document original = new Document();
original.setTitle("Important");
Document copy = original.clone();

2. Структурные паттерны (Structural)

Решают задачи построения сложных структур из классов и объектов.

Adapter (Адаптер)

Позволяет несовместимым интерфейсам работать вместе.

public interface Target {
    void request();
}

public class Adaptee {
    public void specificRequest() {
        System.out.println("Specific request");
    }
}

public class Adapter implements Target {
    private Adaptee adaptee;
    
    public Adapter(Adaptee adaptee) {
        this.adaptee = adaptee;
    }
    
    @Override
    public void request() {
        adaptee.specificRequest();  // Преобразование интерфейса
    }
}

Proxy (Прокси)

Предоставляет заменитель или место-держатель для другого объекта для управления доступом.

public interface Image {
    void display();
}

public class ProxyImage implements Image {
    private String filename;
    private Image realImage;
    
    public ProxyImage(String filename) {
        this.filename = filename;
    }
    
    @Override
    public void display() {
        if (realImage == null) {
            realImage = new RealImage(filename);  // Ленивая загрузка
        }
        realImage.display();
    }
}

Decorator (Декоратор)

Добавляет новую функциональность к существующему объекту динамически.

public interface Coffee {
    double getCost();
    String getDescription();
}

public class SimpleCoffee implements Coffee {
    @Override
    public double getCost() { return 2.0; }
    
    @Override
    public String getDescription() { return "Coffee"; }
}

public class CoffeeWithMilk implements Coffee {
    private Coffee coffee;
    
    public CoffeeWithMilk(Coffee coffee) {
        this.coffee = coffee;
    }
    
    @Override
    public double getCost() { return coffee.getCost() + 0.5; }
    
    @Override
    public String getDescription() { return coffee.getDescription() + ", Milk"; }
}

// Использование
Coffee coffee = new SimpleCoffee();  // 2.0
coffee = new CoffeeWithMilk(coffee);  // 2.5
coffee = new CoffeeWithSugar(coffee);  // 2.7

3. Поведенческие паттерны (Behavioral)

Решают задачи взаимодействия между объектами и распределения ответственности.

Observer (Наблюдатель)

Определяет отношение один-ко-многим между объектами так, чтобы при изменении состояния одного объекта все его зависимые объекты автоматически уведомлялись.

public class Subject {
    private List<Observer> observers = new ArrayList<>();
    
    public void attach(Observer observer) {
        observers.add(observer);
    }
    
    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}

public interface Observer {
    void update(String message);
}

public class ConcreteObserver implements Observer {
    @Override
    public void update(String message) {
        System.out.println("Received: " + message);
    }
}

Strategy (Стратегия)

Определяет семейство алгоритмов, инкапсулирует каждый и делает их взаимозаменяемыми.

public interface PaymentStrategy {
    void pay(double amount);
}

public class CreditCardPayment implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " with credit card");
    }
}

public class PayPalPayment implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("Paid " + amount + " with PayPal");
    }
}

public class ShoppingCart {
    private PaymentStrategy paymentStrategy;
    
    public void setPaymentStrategy(PaymentStrategy strategy) {
        this.paymentStrategy = strategy;
    }
    
    public void checkout(double total) {
        paymentStrategy.pay(total);
    }
}

// Использование
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment());
cart.checkout(100);

Command (Команда)

Инкапсулирует запрос как объект для параметризации клиентов с различными запросами.

public interface Command {
    void execute();
    void undo();
}

public class LightOnCommand implements Command {
    private Light light;
    
    public LightOnCommand(Light light) {
        this.light = light;
    }
    
    @Override
    public void execute() { light.on(); }
    
    @Override
    public void undo() { light.off(); }
}

public class RemoteControl {
    private Command lastCommand;
    
    public void press(Command command) {
        command.execute();
        lastCommand = command;
    }
    
    public void undoLastCommand() {
        lastCommand.undo();
    }
}

Когда использовать какой паттерн

ПроблемаПаттерн
Нужен единственный экземплярSingleton
Создание объектов без указания классаFactory
Сложное построение объектаBuilder
Несовместимые интерфейсыAdapter
Управление доступом к объектуProxy
Добавление функции к объектуDecorator
Уведомление нескольких объектов об измененияхObserver
Разные способы выполнить задачуStrategy
Инкапсуляция операцииCommand

Рекомендации

  1. Не переусложняй — используй паттерны когда они решают реальную проблему
  2. Знай SOLID — большинство паттернов применяют SOLID принципы
  3. Используй Spring для реализации — многие паттерны уже встроены в Spring (Singleton scope, Factory, Proxy через AOP)
  4. Читай исходный код — изучай как реализованы паттерны в известных фреймворках

Заключение

Паттерны программирования — это язык для описания решений. Они помогают:

  • Быстрее разрабатывать
  • Избегать ошибок
  • Говорить с командой на одном языке
  • Делать код гибким и переиспользуемым

Основные паттерны: Singleton, Factory, Builder, Adapter, Decorator, Observer, Strategy, Command. Изучи их и применяй разумно.

Что такое паттерны программирования? | PrepBro